mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Auto merge of #119258 - compiler-errors:closure-kind, r=eholk
Make closures carry their own ClosureKind Right now, we use the "`movability`" field of `hir::Closure` to distinguish a closure and a coroutine. This is paired together with the `CoroutineKind`, which is located not in the `hir::Closure`, but the `hir::Body`. This is strange and redundant. This PR introduces `ClosureKind` with two variants -- `Closure` and `Coroutine`, which is put into `hir::Closure`. The `CoroutineKind` is thus removed from `hir::Body`, and `Option<Movability>` no longer needs to be a stand-in for "is this a closure or a coroutine". r? eholk
This commit is contained in:
commit
1ab783112a
@ -668,11 +668,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
};
|
};
|
||||||
let params = arena_vec![self; param];
|
let params = arena_vec![self; param];
|
||||||
|
|
||||||
|
let coroutine_kind =
|
||||||
|
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, async_coroutine_source);
|
||||||
let body = self.lower_body(move |this| {
|
let body = self.lower_body(move |this| {
|
||||||
this.coroutine_kind = Some(hir::CoroutineKind::Desugared(
|
this.coroutine_kind = Some(coroutine_kind);
|
||||||
hir::CoroutineDesugaring::Async,
|
|
||||||
async_coroutine_source,
|
|
||||||
));
|
|
||||||
|
|
||||||
let old_ctx = this.task_context;
|
let old_ctx = this.task_context;
|
||||||
this.task_context = Some(task_context_hid);
|
this.task_context = Some(task_context_hid);
|
||||||
@ -691,7 +690,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
body,
|
body,
|
||||||
fn_decl_span: self.lower_span(span),
|
fn_decl_span: self.lower_span(span),
|
||||||
fn_arg_span: None,
|
fn_arg_span: None,
|
||||||
movability: Some(hir::Movability::Static),
|
kind: hir::ClosureKind::Coroutine(coroutine_kind),
|
||||||
constness: hir::Constness::NotConst,
|
constness: hir::Constness::NotConst,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -725,11 +724,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
lifetime_elision_allowed: false,
|
lifetime_elision_allowed: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let coroutine_kind =
|
||||||
|
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, coroutine_source);
|
||||||
let body = self.lower_body(move |this| {
|
let body = self.lower_body(move |this| {
|
||||||
this.coroutine_kind = Some(hir::CoroutineKind::Desugared(
|
this.coroutine_kind = Some(coroutine_kind);
|
||||||
hir::CoroutineDesugaring::Gen,
|
|
||||||
coroutine_source,
|
|
||||||
));
|
|
||||||
|
|
||||||
let res = body(this);
|
let res = body(this);
|
||||||
(&[], res)
|
(&[], res)
|
||||||
@ -745,7 +743,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
body,
|
body,
|
||||||
fn_decl_span: self.lower_span(span),
|
fn_decl_span: self.lower_span(span),
|
||||||
fn_arg_span: None,
|
fn_arg_span: None,
|
||||||
movability: Some(Movability::Movable),
|
kind: hir::ClosureKind::Coroutine(coroutine_kind),
|
||||||
constness: hir::Constness::NotConst,
|
constness: hir::Constness::NotConst,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -806,11 +804,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
};
|
};
|
||||||
let params = arena_vec![self; param];
|
let params = arena_vec![self; param];
|
||||||
|
|
||||||
let body = self.lower_body(move |this| {
|
let coroutine_kind = hir::CoroutineKind::Desugared(
|
||||||
this.coroutine_kind = Some(hir::CoroutineKind::Desugared(
|
|
||||||
hir::CoroutineDesugaring::AsyncGen,
|
hir::CoroutineDesugaring::AsyncGen,
|
||||||
async_coroutine_source,
|
async_coroutine_source,
|
||||||
));
|
);
|
||||||
|
let body = self.lower_body(move |this| {
|
||||||
|
this.coroutine_kind = Some(coroutine_kind);
|
||||||
|
|
||||||
let old_ctx = this.task_context;
|
let old_ctx = this.task_context;
|
||||||
this.task_context = Some(task_context_hid);
|
this.task_context = Some(task_context_hid);
|
||||||
@ -829,7 +828,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
body,
|
body,
|
||||||
fn_decl_span: self.lower_span(span),
|
fn_decl_span: self.lower_span(span),
|
||||||
fn_arg_span: None,
|
fn_arg_span: None,
|
||||||
movability: Some(hir::Movability::Static),
|
kind: hir::ClosureKind::Coroutine(coroutine_kind),
|
||||||
constness: hir::Constness::NotConst,
|
constness: hir::Constness::NotConst,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -898,7 +897,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
let is_async_gen = match self.coroutine_kind {
|
let is_async_gen = match self.coroutine_kind {
|
||||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => false,
|
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => false,
|
||||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,
|
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,
|
||||||
Some(hir::CoroutineKind::Coroutine)
|
Some(hir::CoroutineKind::Coroutine(_))
|
||||||
| Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _))
|
| Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _))
|
||||||
| None => {
|
| None => {
|
||||||
return hir::ExprKind::Err(self.dcx().emit_err(AwaitOnlyInAsyncFnAndBlocks {
|
return hir::ExprKind::Err(self.dcx().emit_err(AwaitOnlyInAsyncFnAndBlocks {
|
||||||
@ -1086,7 +1085,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
) -> hir::ExprKind<'hir> {
|
) -> hir::ExprKind<'hir> {
|
||||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||||
|
|
||||||
let (body_id, coroutine_option) = self.with_new_scopes(fn_decl_span, move |this| {
|
let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {
|
||||||
let mut coroutine_kind = None;
|
let mut coroutine_kind = None;
|
||||||
let body_id = this.lower_fn_body(decl, |this| {
|
let body_id = this.lower_fn_body(decl, |this| {
|
||||||
let e = this.lower_expr_mut(body);
|
let e = this.lower_expr_mut(body);
|
||||||
@ -1094,7 +1093,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
e
|
e
|
||||||
});
|
});
|
||||||
let coroutine_option =
|
let coroutine_option =
|
||||||
this.coroutine_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability);
|
this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability);
|
||||||
(body_id, coroutine_option)
|
(body_id, coroutine_option)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1111,26 +1110,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
body: body_id,
|
body: body_id,
|
||||||
fn_decl_span: self.lower_span(fn_decl_span),
|
fn_decl_span: self.lower_span(fn_decl_span),
|
||||||
fn_arg_span: Some(self.lower_span(fn_arg_span)),
|
fn_arg_span: Some(self.lower_span(fn_arg_span)),
|
||||||
movability: coroutine_option,
|
kind: closure_kind,
|
||||||
constness: self.lower_constness(constness),
|
constness: self.lower_constness(constness),
|
||||||
});
|
});
|
||||||
|
|
||||||
hir::ExprKind::Closure(c)
|
hir::ExprKind::Closure(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn coroutine_movability_for_fn(
|
fn closure_movability_for_fn(
|
||||||
&mut self,
|
&mut self,
|
||||||
decl: &FnDecl,
|
decl: &FnDecl,
|
||||||
fn_decl_span: Span,
|
fn_decl_span: Span,
|
||||||
coroutine_kind: Option<hir::CoroutineKind>,
|
coroutine_kind: Option<hir::CoroutineKind>,
|
||||||
movability: Movability,
|
movability: Movability,
|
||||||
) -> Option<hir::Movability> {
|
) -> hir::ClosureKind {
|
||||||
match coroutine_kind {
|
match coroutine_kind {
|
||||||
Some(hir::CoroutineKind::Coroutine) => {
|
Some(hir::CoroutineKind::Coroutine(_)) => {
|
||||||
if decl.inputs.len() > 1 {
|
if decl.inputs.len() > 1 {
|
||||||
self.dcx().emit_err(CoroutineTooManyParameters { fn_decl_span });
|
self.dcx().emit_err(CoroutineTooManyParameters { fn_decl_span });
|
||||||
}
|
}
|
||||||
Some(movability)
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(movability))
|
||||||
}
|
}
|
||||||
Some(
|
Some(
|
||||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
|
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
|
||||||
@ -1143,7 +1142,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
if movability == Movability::Static {
|
if movability == Movability::Static {
|
||||||
self.dcx().emit_err(ClosureCannotBeStatic { fn_decl_span });
|
self.dcx().emit_err(ClosureCannotBeStatic { fn_decl_span });
|
||||||
}
|
}
|
||||||
None
|
hir::ClosureKind::Closure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1235,7 +1234,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
body,
|
body,
|
||||||
fn_decl_span: self.lower_span(fn_decl_span),
|
fn_decl_span: self.lower_span(fn_decl_span),
|
||||||
fn_arg_span: Some(self.lower_span(fn_arg_span)),
|
fn_arg_span: Some(self.lower_span(fn_arg_span)),
|
||||||
movability: None,
|
kind: hir::ClosureKind::Closure,
|
||||||
constness: hir::Constness::NotConst,
|
constness: hir::Constness::NotConst,
|
||||||
});
|
});
|
||||||
hir::ExprKind::Closure(c)
|
hir::ExprKind::Closure(c)
|
||||||
@ -1655,7 +1654,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
self.dcx().emit_err(AsyncCoroutinesNotSupported { span }),
|
self.dcx().emit_err(AsyncCoroutinesNotSupported { span }),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Some(hir::CoroutineKind::Coroutine) | None => {
|
Some(hir::CoroutineKind::Coroutine(_)) => {
|
||||||
if !self.tcx.features().coroutines {
|
if !self.tcx.features().coroutines {
|
||||||
rustc_session::parse::feature_err(
|
rustc_session::parse::feature_err(
|
||||||
&self.tcx.sess.parse_sess,
|
&self.tcx.sess.parse_sess,
|
||||||
@ -1665,7 +1664,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
self.coroutine_kind = Some(hir::CoroutineKind::Coroutine);
|
false
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if !self.tcx.features().coroutines {
|
||||||
|
rustc_session::parse::feature_err(
|
||||||
|
&self.tcx.sess.parse_sess,
|
||||||
|
sym::coroutines,
|
||||||
|
span,
|
||||||
|
"yield syntax is experimental",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable));
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -952,11 +952,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
params: &'hir [hir::Param<'hir>],
|
params: &'hir [hir::Param<'hir>],
|
||||||
value: hir::Expr<'hir>,
|
value: hir::Expr<'hir>,
|
||||||
) -> hir::BodyId {
|
) -> hir::BodyId {
|
||||||
let body = hir::Body {
|
let body = hir::Body { params, value: self.arena.alloc(value) };
|
||||||
coroutine_kind: self.coroutine_kind,
|
|
||||||
params,
|
|
||||||
value: self.arena.alloc(value),
|
|
||||||
};
|
|
||||||
let id = body.id();
|
let id = body.id();
|
||||||
debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
|
debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
|
||||||
self.bodies.push((id.hir_id.local_id, self.arena.alloc(body)));
|
self.bodies.push((id.hir_id.local_id, self.arena.alloc(body)));
|
||||||
|
@ -848,8 +848,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
move_spans.var_subdiag(None, &mut err, None, |kind, var_span| {
|
move_spans.var_subdiag(None, &mut err, None, |kind, var_span| {
|
||||||
use crate::session_diagnostics::CaptureVarCause::*;
|
use crate::session_diagnostics::CaptureVarCause::*;
|
||||||
match kind {
|
match kind {
|
||||||
Some(_) => MoveUseInCoroutine { var_span },
|
hir::ClosureKind::Coroutine(_) => MoveUseInCoroutine { var_span },
|
||||||
None => MoveUseInClosure { var_span },
|
hir::ClosureKind::Closure => MoveUseInClosure { var_span },
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -893,10 +893,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
let place = &borrow.borrowed_place;
|
let place = &borrow.borrowed_place;
|
||||||
let desc_place = self.describe_any_place(place.as_ref());
|
let desc_place = self.describe_any_place(place.as_ref());
|
||||||
match kind {
|
match kind {
|
||||||
Some(_) => {
|
hir::ClosureKind::Coroutine(_) => {
|
||||||
BorrowUsePlaceCoroutine { place: desc_place, var_span, is_single_var: true }
|
BorrowUsePlaceCoroutine { place: desc_place, var_span, is_single_var: true }
|
||||||
}
|
}
|
||||||
None => BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true },
|
hir::ClosureKind::Closure => {
|
||||||
|
BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1040,12 +1042,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
|kind, var_span| {
|
|kind, var_span| {
|
||||||
use crate::session_diagnostics::CaptureVarCause::*;
|
use crate::session_diagnostics::CaptureVarCause::*;
|
||||||
match kind {
|
match kind {
|
||||||
Some(_) => BorrowUsePlaceCoroutine {
|
hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {
|
||||||
place: desc_place,
|
place: desc_place,
|
||||||
var_span,
|
var_span,
|
||||||
is_single_var: true,
|
is_single_var: true,
|
||||||
},
|
},
|
||||||
None => BorrowUsePlaceClosure {
|
hir::ClosureKind::Closure => BorrowUsePlaceClosure {
|
||||||
place: desc_place,
|
place: desc_place,
|
||||||
var_span,
|
var_span,
|
||||||
is_single_var: true,
|
is_single_var: true,
|
||||||
@ -1124,12 +1126,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
borrow_spans.var_subdiag(None, &mut err, Some(gen_borrow_kind), |kind, var_span| {
|
borrow_spans.var_subdiag(None, &mut err, Some(gen_borrow_kind), |kind, var_span| {
|
||||||
use crate::session_diagnostics::CaptureVarCause::*;
|
use crate::session_diagnostics::CaptureVarCause::*;
|
||||||
match kind {
|
match kind {
|
||||||
Some(_) => BorrowUsePlaceCoroutine {
|
hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {
|
||||||
place: desc_place,
|
place: desc_place,
|
||||||
var_span,
|
var_span,
|
||||||
is_single_var: false,
|
is_single_var: false,
|
||||||
},
|
},
|
||||||
None => {
|
hir::ClosureKind::Closure => {
|
||||||
BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false }
|
BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1144,10 +1146,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
let borrow_place = &issued_borrow.borrowed_place;
|
let borrow_place = &issued_borrow.borrowed_place;
|
||||||
let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
|
let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
|
||||||
match kind {
|
match kind {
|
||||||
Some(_) => {
|
hir::ClosureKind::Coroutine(_) => {
|
||||||
FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span }
|
FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span }
|
||||||
}
|
}
|
||||||
None => FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span },
|
hir::ClosureKind::Closure => {
|
||||||
|
FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -1159,8 +1163,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
|kind, var_span| {
|
|kind, var_span| {
|
||||||
use crate::session_diagnostics::CaptureVarCause::*;
|
use crate::session_diagnostics::CaptureVarCause::*;
|
||||||
match kind {
|
match kind {
|
||||||
Some(_) => SecondBorrowUsePlaceCoroutine { place: desc_place, var_span },
|
hir::ClosureKind::Coroutine(_) => {
|
||||||
None => SecondBorrowUsePlaceClosure { place: desc_place, var_span },
|
SecondBorrowUsePlaceCoroutine { place: desc_place, var_span }
|
||||||
|
}
|
||||||
|
hir::ClosureKind::Closure => {
|
||||||
|
SecondBorrowUsePlaceClosure { place: desc_place, var_span }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -1651,7 +1659,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
|
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
|
||||||
if e.span.contains(self.capture_span) {
|
if e.span.contains(self.capture_span) {
|
||||||
if let hir::ExprKind::Closure(&hir::Closure {
|
if let hir::ExprKind::Closure(&hir::Closure {
|
||||||
movability: None,
|
kind: hir::ClosureKind::Closure,
|
||||||
body,
|
body,
|
||||||
fn_arg_span,
|
fn_arg_span,
|
||||||
fn_decl: hir::FnDecl { inputs, .. },
|
fn_decl: hir::FnDecl { inputs, .. },
|
||||||
@ -1686,7 +1694,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
&& let Some(init) = local.init
|
&& let Some(init) = local.init
|
||||||
{
|
{
|
||||||
if let hir::Expr {
|
if let hir::Expr {
|
||||||
kind: hir::ExprKind::Closure(&hir::Closure { movability: None, .. }),
|
kind:
|
||||||
|
hir::ExprKind::Closure(&hir::Closure {
|
||||||
|
kind: hir::ClosureKind::Closure,
|
||||||
|
..
|
||||||
|
}),
|
||||||
..
|
..
|
||||||
} = init
|
} = init
|
||||||
&& init.span.contains(self.capture_span)
|
&& init.span.contains(self.capture_span)
|
||||||
@ -2537,7 +2549,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CoroutineKind::Coroutine => "coroutine",
|
CoroutineKind::Coroutine(_) => "coroutine",
|
||||||
},
|
},
|
||||||
None => "closure",
|
None => "closure",
|
||||||
};
|
};
|
||||||
@ -2838,8 +2850,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
|
loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
|
||||||
use crate::session_diagnostics::CaptureVarCause::*;
|
use crate::session_diagnostics::CaptureVarCause::*;
|
||||||
match kind {
|
match kind {
|
||||||
Some(_) => BorrowUseInCoroutine { var_span },
|
hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
|
||||||
None => BorrowUseInClosure { var_span },
|
hir::ClosureKind::Closure => BorrowUseInClosure { var_span },
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2854,8 +2866,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
|
loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
|
||||||
use crate::session_diagnostics::CaptureVarCause::*;
|
use crate::session_diagnostics::CaptureVarCause::*;
|
||||||
match kind {
|
match kind {
|
||||||
Some(_) => BorrowUseInCoroutine { var_span },
|
hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
|
||||||
None => BorrowUseInClosure { var_span },
|
hir::ClosureKind::Closure => BorrowUseInClosure { var_span },
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -505,7 +505,7 @@ pub(super) enum UseSpans<'tcx> {
|
|||||||
/// The access is caused by capturing a variable for a closure.
|
/// The access is caused by capturing a variable for a closure.
|
||||||
ClosureUse {
|
ClosureUse {
|
||||||
/// This is true if the captured variable was from a coroutine.
|
/// This is true if the captured variable was from a coroutine.
|
||||||
coroutine_kind: Option<CoroutineKind>,
|
closure_kind: hir::ClosureKind,
|
||||||
/// The span of the args of the closure, including the `move` keyword if
|
/// The span of the args of the closure, including the `move` keyword if
|
||||||
/// it's present.
|
/// it's present.
|
||||||
args_span: Span,
|
args_span: Span,
|
||||||
@ -572,9 +572,13 @@ impl UseSpans<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(coroutines): Make this just return the `ClosureKind` directly?
|
||||||
pub(super) fn coroutine_kind(self) -> Option<CoroutineKind> {
|
pub(super) fn coroutine_kind(self) -> Option<CoroutineKind> {
|
||||||
match self {
|
match self {
|
||||||
UseSpans::ClosureUse { coroutine_kind, .. } => coroutine_kind,
|
UseSpans::ClosureUse {
|
||||||
|
closure_kind: hir::ClosureKind::Coroutine(coroutine_kind),
|
||||||
|
..
|
||||||
|
} => Some(coroutine_kind),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -599,9 +603,9 @@ impl UseSpans<'_> {
|
|||||||
) {
|
) {
|
||||||
use crate::InitializationRequiringAction::*;
|
use crate::InitializationRequiringAction::*;
|
||||||
use CaptureVarPathUseCause::*;
|
use CaptureVarPathUseCause::*;
|
||||||
if let UseSpans::ClosureUse { coroutine_kind, path_span, .. } = self {
|
if let UseSpans::ClosureUse { closure_kind, path_span, .. } = self {
|
||||||
match coroutine_kind {
|
match closure_kind {
|
||||||
Some(_) => {
|
hir::ClosureKind::Coroutine(_) => {
|
||||||
err.subdiagnostic(match action {
|
err.subdiagnostic(match action {
|
||||||
Borrow => BorrowInCoroutine { path_span },
|
Borrow => BorrowInCoroutine { path_span },
|
||||||
MatchOn | Use => UseInCoroutine { path_span },
|
MatchOn | Use => UseInCoroutine { path_span },
|
||||||
@ -609,7 +613,7 @@ impl UseSpans<'_> {
|
|||||||
PartialAssignment => AssignPartInCoroutine { path_span },
|
PartialAssignment => AssignPartInCoroutine { path_span },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
None => {
|
hir::ClosureKind::Closure => {
|
||||||
err.subdiagnostic(match action {
|
err.subdiagnostic(match action {
|
||||||
Borrow => BorrowInClosure { path_span },
|
Borrow => BorrowInClosure { path_span },
|
||||||
MatchOn | Use => UseInClosure { path_span },
|
MatchOn | Use => UseInClosure { path_span },
|
||||||
@ -627,9 +631,9 @@ impl UseSpans<'_> {
|
|||||||
dcx: Option<&rustc_errors::DiagCtxt>,
|
dcx: Option<&rustc_errors::DiagCtxt>,
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
kind: Option<rustc_middle::mir::BorrowKind>,
|
kind: Option<rustc_middle::mir::BorrowKind>,
|
||||||
f: impl FnOnce(Option<CoroutineKind>, Span) -> CaptureVarCause,
|
f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause,
|
||||||
) {
|
) {
|
||||||
if let UseSpans::ClosureUse { coroutine_kind, capture_kind_span, path_span, .. } = self {
|
if let UseSpans::ClosureUse { closure_kind, capture_kind_span, path_span, .. } = self {
|
||||||
if capture_kind_span != path_span {
|
if capture_kind_span != path_span {
|
||||||
err.subdiagnostic(match kind {
|
err.subdiagnostic(match kind {
|
||||||
Some(kd) => match kd {
|
Some(kd) => match kd {
|
||||||
@ -645,7 +649,7 @@ impl UseSpans<'_> {
|
|||||||
None => CaptureVarKind::Move { kind_span: capture_kind_span },
|
None => CaptureVarKind::Move { kind_span: capture_kind_span },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
let diag = f(coroutine_kind, path_span);
|
let diag = f(closure_kind, path_span);
|
||||||
match dcx {
|
match dcx {
|
||||||
Some(hd) => err.eager_subdiagnostic(hd, diag),
|
Some(hd) => err.eager_subdiagnostic(hd, diag),
|
||||||
None => err.subdiagnostic(diag),
|
None => err.subdiagnostic(diag),
|
||||||
@ -656,7 +660,9 @@ impl UseSpans<'_> {
|
|||||||
/// Returns `false` if this place is not used in a closure.
|
/// Returns `false` if this place is not used in a closure.
|
||||||
pub(super) fn for_closure(&self) -> bool {
|
pub(super) fn for_closure(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
UseSpans::ClosureUse { coroutine_kind, .. } => coroutine_kind.is_none(),
|
UseSpans::ClosureUse { closure_kind, .. } => {
|
||||||
|
matches!(closure_kind, hir::ClosureKind::Closure)
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -664,7 +670,10 @@ impl UseSpans<'_> {
|
|||||||
/// Returns `false` if this place is not used in a coroutine.
|
/// Returns `false` if this place is not used in a coroutine.
|
||||||
pub(super) fn for_coroutine(&self) -> bool {
|
pub(super) fn for_coroutine(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
UseSpans::ClosureUse { coroutine_kind, .. } => coroutine_kind.is_some(),
|
// FIXME(coroutines): Do we want this to apply to synthetic coroutines?
|
||||||
|
UseSpans::ClosureUse { closure_kind, .. } => {
|
||||||
|
matches!(closure_kind, hir::ClosureKind::Coroutine(..))
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -788,10 +797,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
{
|
{
|
||||||
debug!("move_spans: def_id={:?} places={:?}", def_id, places);
|
debug!("move_spans: def_id={:?} places={:?}", def_id, places);
|
||||||
let def_id = def_id.expect_local();
|
let def_id = def_id.expect_local();
|
||||||
if let Some((args_span, coroutine_kind, capture_kind_span, path_span)) =
|
if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
|
||||||
self.closure_span(def_id, moved_place, places)
|
self.closure_span(def_id, moved_place, places)
|
||||||
{
|
{
|
||||||
return ClosureUse { coroutine_kind, args_span, capture_kind_span, path_span };
|
return ClosureUse { closure_kind, args_span, capture_kind_span, path_span };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -803,11 +812,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
| FakeReadCause::ForLet(Some(closure_def_id)) => {
|
| FakeReadCause::ForLet(Some(closure_def_id)) => {
|
||||||
debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
|
debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
|
||||||
let places = &[Operand::Move(place)];
|
let places = &[Operand::Move(place)];
|
||||||
if let Some((args_span, coroutine_kind, capture_kind_span, path_span)) =
|
if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
|
||||||
self.closure_span(closure_def_id, moved_place, IndexSlice::from_raw(places))
|
self.closure_span(closure_def_id, moved_place, IndexSlice::from_raw(places))
|
||||||
{
|
{
|
||||||
return ClosureUse {
|
return ClosureUse {
|
||||||
coroutine_kind,
|
closure_kind,
|
||||||
args_span,
|
args_span,
|
||||||
capture_kind_span,
|
capture_kind_span,
|
||||||
path_span,
|
path_span,
|
||||||
@ -928,10 +937,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
"borrow_spans: def_id={:?} is_coroutine={:?} places={:?}",
|
"borrow_spans: def_id={:?} is_coroutine={:?} places={:?}",
|
||||||
def_id, is_coroutine, places
|
def_id, is_coroutine, places
|
||||||
);
|
);
|
||||||
if let Some((args_span, coroutine_kind, capture_kind_span, path_span)) =
|
if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
|
||||||
self.closure_span(def_id, Place::from(target).as_ref(), places)
|
self.closure_span(def_id, Place::from(target).as_ref(), places)
|
||||||
{
|
{
|
||||||
return ClosureUse { coroutine_kind, args_span, capture_kind_span, path_span };
|
return ClosureUse { closure_kind, args_span, capture_kind_span, path_span };
|
||||||
} else {
|
} else {
|
||||||
return OtherUse(use_span);
|
return OtherUse(use_span);
|
||||||
}
|
}
|
||||||
@ -953,7 +962,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
def_id: LocalDefId,
|
def_id: LocalDefId,
|
||||||
target_place: PlaceRef<'tcx>,
|
target_place: PlaceRef<'tcx>,
|
||||||
places: &IndexSlice<FieldIdx, Operand<'tcx>>,
|
places: &IndexSlice<FieldIdx, Operand<'tcx>>,
|
||||||
) -> Option<(Span, Option<CoroutineKind>, Span, Span)> {
|
) -> Option<(Span, hir::ClosureKind, Span, Span)> {
|
||||||
debug!(
|
debug!(
|
||||||
"closure_span: def_id={:?} target_place={:?} places={:?}",
|
"closure_span: def_id={:?} target_place={:?} places={:?}",
|
||||||
def_id, target_place, places
|
def_id, target_place, places
|
||||||
@ -961,7 +970,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
let hir_id = self.infcx.tcx.local_def_id_to_hir_id(def_id);
|
let hir_id = self.infcx.tcx.local_def_id_to_hir_id(def_id);
|
||||||
let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
|
let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
|
||||||
debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
|
debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
|
||||||
if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr {
|
if let hir::ExprKind::Closure(&hir::Closure { kind, fn_decl_span, .. }) = expr {
|
||||||
for (captured_place, place) in
|
for (captured_place, place) in
|
||||||
self.infcx.tcx.closure_captures(def_id).iter().zip(places)
|
self.infcx.tcx.closure_captures(def_id).iter().zip(places)
|
||||||
{
|
{
|
||||||
@ -970,12 +979,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
if target_place == place.as_ref() =>
|
if target_place == place.as_ref() =>
|
||||||
{
|
{
|
||||||
debug!("closure_span: found captured local {:?}", place);
|
debug!("closure_span: found captured local {:?}", place);
|
||||||
let body = self.infcx.tcx.hir().body(body);
|
|
||||||
let coroutine_kind = body.coroutine_kind();
|
|
||||||
|
|
||||||
return Some((
|
return Some((
|
||||||
fn_decl_span,
|
fn_decl_span,
|
||||||
coroutine_kind,
|
kind,
|
||||||
captured_place.get_capture_kind_span(self.infcx.tcx),
|
captured_place.get_capture_kind_span(self.infcx.tcx),
|
||||||
captured_place.get_path_span(self.infcx.tcx),
|
captured_place.get_path_span(self.infcx.tcx),
|
||||||
));
|
));
|
||||||
@ -1242,8 +1248,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
// another message for the same span
|
// another message for the same span
|
||||||
if !is_loop_message {
|
if !is_loop_message {
|
||||||
move_spans.var_subdiag(None, err, None, |kind, var_span| match kind {
|
move_spans.var_subdiag(None, err, None, |kind, var_span| match kind {
|
||||||
Some(_) => CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial },
|
hir::ClosureKind::Coroutine(_) => {
|
||||||
None => CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial },
|
CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial }
|
||||||
|
}
|
||||||
|
hir::ClosureKind::Closure => {
|
||||||
|
CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial }
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1030,8 +1030,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
let hir = self.infcx.tcx.hir();
|
let hir = self.infcx.tcx.hir();
|
||||||
if let InstanceDef::Item(def_id) = source.instance
|
if let InstanceDef::Item(def_id) = source.instance
|
||||||
&& let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id)
|
&& let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id)
|
||||||
&& let ExprKind::Closure(closure) = kind
|
&& let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind
|
||||||
&& closure.movability == None
|
|
||||||
&& let Some(Node::Expr(expr)) = hir.find_parent(*hir_id)
|
&& let Some(Node::Expr(expr)) = hir.find_parent(*hir_id)
|
||||||
{
|
{
|
||||||
let mut cur_expr = expr;
|
let mut cur_expr = expr;
|
||||||
|
@ -1041,13 +1041,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
hir::ExprKind::Closure(hir::Closure {
|
hir::ExprKind::Closure(hir::Closure {
|
||||||
capture_clause: hir::CaptureBy::Ref,
|
capture_clause: hir::CaptureBy::Ref,
|
||||||
body,
|
kind,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
let body = map.body(*body);
|
|
||||||
if !matches!(
|
if !matches!(
|
||||||
body.coroutine_kind,
|
kind,
|
||||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _))
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||||
|
hir::CoroutineDesugaring::Async,
|
||||||
|
_
|
||||||
|
),)
|
||||||
) {
|
) {
|
||||||
closure_span = Some(expr.span.shrink_to_lo());
|
closure_span = Some(expr.span.shrink_to_lo());
|
||||||
}
|
}
|
||||||
|
@ -674,7 +674,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||||||
|
|
||||||
let (return_span, mir_description, hir_ty) = match tcx.hir_node(mir_hir_id) {
|
let (return_span, mir_description, hir_ty) = match tcx.hir_node(mir_hir_id) {
|
||||||
hir::Node::Expr(hir::Expr {
|
hir::Node::Expr(hir::Expr {
|
||||||
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl, body, fn_decl_span, .. }),
|
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl, kind, fn_decl_span, .. }),
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
let (mut span, mut hir_ty) = match fn_decl.output {
|
let (mut span, mut hir_ty) = match fn_decl.output {
|
||||||
@ -683,12 +683,21 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)),
|
hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)),
|
||||||
};
|
};
|
||||||
let mir_description = match hir.body(body).coroutine_kind {
|
let mir_description = match kind {
|
||||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, src)) => {
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||||
match src {
|
hir::CoroutineDesugaring::Async,
|
||||||
hir::CoroutineSource::Block => " of async block",
|
hir::CoroutineSource::Block,
|
||||||
hir::CoroutineSource::Closure => " of async closure",
|
)) => " of async block",
|
||||||
hir::CoroutineSource::Fn => {
|
|
||||||
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||||
|
hir::CoroutineDesugaring::Async,
|
||||||
|
hir::CoroutineSource::Closure,
|
||||||
|
)) => " of async closure",
|
||||||
|
|
||||||
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||||
|
hir::CoroutineDesugaring::Async,
|
||||||
|
hir::CoroutineSource::Fn,
|
||||||
|
)) => {
|
||||||
let parent_item =
|
let parent_item =
|
||||||
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
||||||
let output = &parent_item
|
let output = &parent_item
|
||||||
@ -701,13 +710,21 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
" of async function"
|
" of async function"
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, src)) => {
|
hir::CoroutineDesugaring::Gen,
|
||||||
match src {
|
hir::CoroutineSource::Block,
|
||||||
hir::CoroutineSource::Block => " of gen block",
|
)) => " of gen block",
|
||||||
hir::CoroutineSource::Closure => " of gen closure",
|
|
||||||
hir::CoroutineSource::Fn => {
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||||
|
hir::CoroutineDesugaring::Gen,
|
||||||
|
hir::CoroutineSource::Closure,
|
||||||
|
)) => " of gen closure",
|
||||||
|
|
||||||
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||||
|
hir::CoroutineDesugaring::Gen,
|
||||||
|
hir::CoroutineSource::Fn,
|
||||||
|
)) => {
|
||||||
let parent_item =
|
let parent_item =
|
||||||
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
||||||
let output = &parent_item
|
let output = &parent_item
|
||||||
@ -717,16 +734,21 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||||||
span = output.span();
|
span = output.span();
|
||||||
" of gen function"
|
" of gen function"
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(hir::CoroutineKind::Desugared(
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||||
hir::CoroutineDesugaring::AsyncGen,
|
hir::CoroutineDesugaring::AsyncGen,
|
||||||
src,
|
hir::CoroutineSource::Block,
|
||||||
)) => match src {
|
)) => " of async gen block",
|
||||||
hir::CoroutineSource::Block => " of async gen block",
|
|
||||||
hir::CoroutineSource::Closure => " of async gen closure",
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||||
hir::CoroutineSource::Fn => {
|
hir::CoroutineDesugaring::AsyncGen,
|
||||||
|
hir::CoroutineSource::Closure,
|
||||||
|
)) => " of async gen closure",
|
||||||
|
|
||||||
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||||
|
hir::CoroutineDesugaring::AsyncGen,
|
||||||
|
hir::CoroutineSource::Fn,
|
||||||
|
)) => {
|
||||||
let parent_item =
|
let parent_item =
|
||||||
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
||||||
let output = &parent_item
|
let output = &parent_item
|
||||||
@ -736,9 +758,11 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||||||
span = output.span();
|
span = output.span();
|
||||||
" of async gen function"
|
" of async gen function"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
Some(hir::CoroutineKind::Coroutine) => " of coroutine",
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) => {
|
||||||
None => " of closure",
|
" of coroutine"
|
||||||
|
}
|
||||||
|
hir::ClosureKind::Closure => " of closure",
|
||||||
};
|
};
|
||||||
(span, mir_description, hir_ty)
|
(span, mir_description, hir_ty)
|
||||||
}
|
}
|
||||||
|
@ -585,7 +585,7 @@ fn coroutine_kind_label(coroutine_kind: Option<CoroutineKind>) -> &'static str {
|
|||||||
Some(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, CoroutineSource::Fn)) => {
|
Some(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, CoroutineSource::Fn)) => {
|
||||||
"async_gen_fn"
|
"async_gen_fn"
|
||||||
}
|
}
|
||||||
Some(CoroutineKind::Coroutine) => "coroutine",
|
Some(CoroutineKind::Coroutine(_)) => "coroutine",
|
||||||
None => "closure",
|
None => "closure",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -938,8 +938,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||||||
|
|
||||||
TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm),
|
TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm),
|
||||||
|
|
||||||
TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } => {
|
TerminatorKind::Yield { .. } => self.check_op(ops::Coroutine(
|
||||||
self.check_op(ops::Coroutine(hir::CoroutineKind::Coroutine))
|
self.tcx
|
||||||
|
.coroutine_kind(self.body.source.def_id())
|
||||||
|
.expect("Only expected to have a yield in a coroutine"),
|
||||||
|
)),
|
||||||
|
|
||||||
|
TerminatorKind::CoroutineDrop => {
|
||||||
|
span_bug!(
|
||||||
|
self.body.source_info(location).span,
|
||||||
|
"We should not encounter TerminatorKind::CoroutineDrop after coroutine transform"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminatorKind::UnwindTerminate(_) => {
|
TerminatorKind::UnwindTerminate(_) => {
|
||||||
|
@ -945,7 +945,18 @@ pub struct Closure<'hir> {
|
|||||||
pub fn_decl_span: Span,
|
pub fn_decl_span: Span,
|
||||||
/// The span of the argument block `|...|`
|
/// The span of the argument block `|...|`
|
||||||
pub fn_arg_span: Option<Span>,
|
pub fn_arg_span: Option<Span>,
|
||||||
pub movability: Option<Movability>,
|
pub kind: ClosureKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Debug, Copy, Hash, HashStable_Generic, Encodable, Decodable)]
|
||||||
|
pub enum ClosureKind {
|
||||||
|
/// This is a plain closure expression.
|
||||||
|
Closure,
|
||||||
|
/// This is a coroutine expression -- i.e. a closure expression in which
|
||||||
|
/// we've found a `yield`. These can arise either from "plain" coroutine
|
||||||
|
/// usage (e.g. `let x = || { yield (); }`) or from a desugared expression
|
||||||
|
/// (e.g. `async` and `gen` blocks).
|
||||||
|
Coroutine(CoroutineKind),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A block of statements `{ .. }`, which may have a label (in this case the
|
/// A block of statements `{ .. }`, which may have a label (in this case the
|
||||||
@ -1335,17 +1346,12 @@ pub struct BodyId {
|
|||||||
pub struct Body<'hir> {
|
pub struct Body<'hir> {
|
||||||
pub params: &'hir [Param<'hir>],
|
pub params: &'hir [Param<'hir>],
|
||||||
pub value: &'hir Expr<'hir>,
|
pub value: &'hir Expr<'hir>,
|
||||||
pub coroutine_kind: Option<CoroutineKind>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'hir> Body<'hir> {
|
impl<'hir> Body<'hir> {
|
||||||
pub fn id(&self) -> BodyId {
|
pub fn id(&self) -> BodyId {
|
||||||
BodyId { hir_id: self.value.hir_id }
|
BodyId { hir_id: self.value.hir_id }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn coroutine_kind(&self) -> Option<CoroutineKind> {
|
|
||||||
self.coroutine_kind
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type of source expression that caused this coroutine to be created.
|
/// The type of source expression that caused this coroutine to be created.
|
||||||
@ -1355,7 +1361,18 @@ pub enum CoroutineKind {
|
|||||||
Desugared(CoroutineDesugaring, CoroutineSource),
|
Desugared(CoroutineDesugaring, CoroutineSource),
|
||||||
|
|
||||||
/// A coroutine literal created via a `yield` inside a closure.
|
/// A coroutine literal created via a `yield` inside a closure.
|
||||||
Coroutine,
|
Coroutine(Movability),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CoroutineKind {
|
||||||
|
pub fn movability(self) -> Movability {
|
||||||
|
match self {
|
||||||
|
CoroutineKind::Desugared(CoroutineDesugaring::Async, _)
|
||||||
|
| CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _) => Movability::Static,
|
||||||
|
CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => Movability::Movable,
|
||||||
|
CoroutineKind::Coroutine(mov) => mov,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for CoroutineKind {
|
impl fmt::Display for CoroutineKind {
|
||||||
@ -1365,7 +1382,7 @@ impl fmt::Display for CoroutineKind {
|
|||||||
d.fmt(f)?;
|
d.fmt(f)?;
|
||||||
k.fmt(f)
|
k.fmt(f)
|
||||||
}
|
}
|
||||||
CoroutineKind::Coroutine => f.write_str("coroutine"),
|
CoroutineKind::Coroutine(_) => f.write_str("coroutine"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3661,7 +3678,7 @@ mod size_asserts {
|
|||||||
use super::*;
|
use super::*;
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
static_assert_size!(Block<'_>, 48);
|
static_assert_size!(Block<'_>, 48);
|
||||||
static_assert_size!(Body<'_>, 32);
|
static_assert_size!(Body<'_>, 24);
|
||||||
static_assert_size!(Expr<'_>, 64);
|
static_assert_size!(Expr<'_>, 64);
|
||||||
static_assert_size!(ExprKind<'_>, 48);
|
static_assert_size!(ExprKind<'_>, 48);
|
||||||
static_assert_size!(FnDecl<'_>, 40);
|
static_assert_size!(FnDecl<'_>, 40);
|
||||||
|
@ -757,7 +757,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
|||||||
capture_clause: _,
|
capture_clause: _,
|
||||||
fn_decl_span: _,
|
fn_decl_span: _,
|
||||||
fn_arg_span: _,
|
fn_arg_span: _,
|
||||||
movability: _,
|
kind: _,
|
||||||
constness: _,
|
constness: _,
|
||||||
}) => {
|
}) => {
|
||||||
walk_list!(visitor, visit_generic_param, bound_generic_params);
|
walk_list!(visitor, visit_generic_param, bound_generic_params);
|
||||||
|
@ -824,10 +824,6 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
|
|||||||
resolve_local(self, None, Some(body.value));
|
resolve_local(self, None, Some(body.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if body.coroutine_kind.is_some() {
|
|
||||||
self.scope_tree.body_expr_count.insert(body_id, self.expr_and_pat_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore context we had at the start.
|
// Restore context we had at the start.
|
||||||
self.expr_and_pat_count = outer_ec;
|
self.expr_and_pat_count = outer_ec;
|
||||||
self.cx = outer_cx;
|
self.cx = outer_cx;
|
||||||
|
@ -1551,10 +1551,14 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
|
|||||||
|
|
||||||
fn coroutine_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::CoroutineKind> {
|
fn coroutine_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::CoroutineKind> {
|
||||||
match tcx.hir_node_by_def_id(def_id) {
|
match tcx.hir_node_by_def_id(def_id) {
|
||||||
Node::Expr(&rustc_hir::Expr {
|
Node::Expr(&hir::Expr {
|
||||||
kind: rustc_hir::ExprKind::Closure(&rustc_hir::Closure { body, .. }),
|
kind:
|
||||||
|
hir::ExprKind::Closure(&rustc_hir::Closure {
|
||||||
|
kind: hir::ClosureKind::Coroutine(kind),
|
||||||
..
|
..
|
||||||
}) => tcx.hir().body(body).coroutine_kind(),
|
}),
|
||||||
|
..
|
||||||
|
}) => Some(kind),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -338,14 +338,14 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||||||
// cares about anything but the length is instantiation,
|
// cares about anything but the length is instantiation,
|
||||||
// and we don't do that for closures.
|
// and we don't do that for closures.
|
||||||
if let Node::Expr(&hir::Expr {
|
if let Node::Expr(&hir::Expr {
|
||||||
kind: hir::ExprKind::Closure(hir::Closure { movability: gen, .. }),
|
kind: hir::ExprKind::Closure(hir::Closure { kind, .. }), ..
|
||||||
..
|
|
||||||
}) = node
|
}) = node
|
||||||
{
|
{
|
||||||
let dummy_args = if gen.is_some() {
|
let dummy_args = match kind {
|
||||||
|
ClosureKind::Closure => &["<closure_kind>", "<closure_signature>", "<upvars>"][..],
|
||||||
|
ClosureKind::Coroutine(_) => {
|
||||||
&["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
|
&["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
|
||||||
} else {
|
}
|
||||||
&["<closure_kind>", "<closure_signature>", "<upvars>"][..]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef {
|
params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef {
|
||||||
|
@ -1407,7 +1407,7 @@ impl<'a> State<'a> {
|
|||||||
body,
|
body,
|
||||||
fn_decl_span: _,
|
fn_decl_span: _,
|
||||||
fn_arg_span: _,
|
fn_arg_span: _,
|
||||||
movability: _,
|
kind: _,
|
||||||
def_id: _,
|
def_id: _,
|
||||||
}) => {
|
}) => {
|
||||||
self.print_closure_binder(binder, bound_generic_params);
|
self.print_closure_binder(binder, bound_generic_params);
|
||||||
|
@ -298,17 +298,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let parent_node = self.tcx.hir_node(parent_hir_id);
|
let parent_node = self.tcx.hir_node(parent_hir_id);
|
||||||
if let (
|
if let (
|
||||||
hir::Node::Expr(hir::Expr {
|
hir::Node::Expr(hir::Expr {
|
||||||
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, body, .. }),
|
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, kind, .. }),
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
hir::ExprKind::Block(..),
|
hir::ExprKind::Block(..),
|
||||||
) = (parent_node, callee_node)
|
) = (parent_node, callee_node)
|
||||||
{
|
{
|
||||||
let fn_decl_span = if hir.body(body).coroutine_kind
|
let fn_decl_span = if matches!(
|
||||||
== Some(hir::CoroutineKind::Desugared(
|
kind,
|
||||||
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||||
hir::CoroutineDesugaring::Async,
|
hir::CoroutineDesugaring::Async,
|
||||||
hir::CoroutineSource::Closure,
|
hir::CoroutineSource::Closure
|
||||||
)) {
|
),)
|
||||||
|
) {
|
||||||
// Actually need to unwrap one more layer of HIR to get to
|
// Actually need to unwrap one more layer of HIR to get to
|
||||||
// the _real_ closure...
|
// the _real_ closure...
|
||||||
let async_closure = hir.parent_id(parent_hir_id);
|
let async_closure = hir.parent_id(parent_hir_id);
|
||||||
|
@ -31,7 +31,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||||||
decl: &'tcx hir::FnDecl<'tcx>,
|
decl: &'tcx hir::FnDecl<'tcx>,
|
||||||
fn_def_id: LocalDefId,
|
fn_def_id: LocalDefId,
|
||||||
body: &'tcx hir::Body<'tcx>,
|
body: &'tcx hir::Body<'tcx>,
|
||||||
can_be_coroutine: Option<hir::Movability>,
|
closure_kind: Option<hir::ClosureKind>,
|
||||||
params_can_be_unsized: bool,
|
params_can_be_unsized: bool,
|
||||||
) -> Option<CoroutineTypes<'tcx>> {
|
) -> Option<CoroutineTypes<'tcx>> {
|
||||||
let fn_id = fcx.tcx.local_def_id_to_hir_id(fn_def_id);
|
let fn_id = fcx.tcx.local_def_id_to_hir_id(fn_def_id);
|
||||||
@ -55,12 +55,10 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||||||
|
|
||||||
forbid_intrinsic_abi(tcx, span, fn_sig.abi);
|
forbid_intrinsic_abi(tcx, span, fn_sig.abi);
|
||||||
|
|
||||||
if let Some(kind) = body.coroutine_kind
|
if let Some(hir::ClosureKind::Coroutine(kind)) = closure_kind {
|
||||||
&& can_be_coroutine.is_some()
|
|
||||||
{
|
|
||||||
let yield_ty = match kind {
|
let yield_ty = match kind {
|
||||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
|
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
|
||||||
| hir::CoroutineKind::Coroutine => {
|
| hir::CoroutineKind::Coroutine(_) => {
|
||||||
let yield_ty = fcx.next_ty_var(TypeVariableOrigin {
|
let yield_ty = fcx.next_ty_var(TypeVariableOrigin {
|
||||||
kind: TypeVariableOriginKind::TypeInference,
|
kind: TypeVariableOriginKind::TypeInference,
|
||||||
span,
|
span,
|
||||||
@ -151,9 +149,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||||||
// We insert the deferred_coroutine_interiors entry after visiting the body.
|
// We insert the deferred_coroutine_interiors entry after visiting the body.
|
||||||
// This ensures that all nested coroutines appear before the entry of this coroutine.
|
// This ensures that all nested coroutines appear before the entry of this coroutine.
|
||||||
// resolve_coroutine_interiors relies on this property.
|
// resolve_coroutine_interiors relies on this property.
|
||||||
let coroutine_ty = if let (Some(_), Some(coroutine_kind)) =
|
let coroutine_ty = if let Some(hir::ClosureKind::Coroutine(coroutine_kind)) = closure_kind {
|
||||||
(can_be_coroutine, body.coroutine_kind)
|
|
||||||
{
|
|
||||||
let interior = fcx
|
let interior = fcx
|
||||||
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
|
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
|
||||||
fcx.deferred_coroutine_interiors.borrow_mut().push((
|
fcx.deferred_coroutine_interiors.borrow_mut().push((
|
||||||
@ -168,7 +164,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||||||
resume_ty,
|
resume_ty,
|
||||||
yield_ty,
|
yield_ty,
|
||||||
interior,
|
interior,
|
||||||
movability: can_be_coroutine.unwrap(),
|
movability: coroutine_kind.movability(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -60,25 +60,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
None => (None, None),
|
None => (None, None),
|
||||||
};
|
};
|
||||||
let body = self.tcx.hir().body(closure.body);
|
|
||||||
self.check_closure(closure, expr_span, expected_kind, body, expected_sig)
|
self.check_closure(closure, expr_span, expected_kind, expected_sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self, closure, body), level = "debug", ret)]
|
#[instrument(skip(self, closure), level = "debug", ret)]
|
||||||
fn check_closure(
|
fn check_closure(
|
||||||
&self,
|
&self,
|
||||||
closure: &hir::Closure<'tcx>,
|
closure: &hir::Closure<'tcx>,
|
||||||
expr_span: Span,
|
expr_span: Span,
|
||||||
opt_kind: Option<ty::ClosureKind>,
|
opt_kind: Option<ty::ClosureKind>,
|
||||||
body: &'tcx hir::Body<'tcx>,
|
|
||||||
expected_sig: Option<ExpectedSig<'tcx>>,
|
expected_sig: Option<ExpectedSig<'tcx>>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
|
let body = self.tcx.hir().body(closure.body);
|
||||||
|
|
||||||
trace!("decl = {:#?}", closure.fn_decl);
|
trace!("decl = {:#?}", closure.fn_decl);
|
||||||
let expr_def_id = closure.def_id;
|
let expr_def_id = closure.def_id;
|
||||||
debug!(?expr_def_id);
|
debug!(?expr_def_id);
|
||||||
|
|
||||||
let ClosureSignatures { bound_sig, liberated_sig } =
|
let ClosureSignatures { bound_sig, liberated_sig } =
|
||||||
self.sig_of_closure(expr_def_id, closure.fn_decl, body, expected_sig);
|
self.sig_of_closure(expr_def_id, closure.fn_decl, closure.kind, expected_sig);
|
||||||
|
|
||||||
debug!(?bound_sig, ?liberated_sig);
|
debug!(?bound_sig, ?liberated_sig);
|
||||||
|
|
||||||
@ -89,7 +90,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
closure.fn_decl,
|
closure.fn_decl,
|
||||||
expr_def_id,
|
expr_def_id,
|
||||||
body,
|
body,
|
||||||
closure.movability,
|
Some(closure.kind),
|
||||||
// Closure "rust-call" ABI doesn't support unsized params
|
// Closure "rust-call" ABI doesn't support unsized params
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
@ -351,28 +352,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
&self,
|
&self,
|
||||||
expr_def_id: LocalDefId,
|
expr_def_id: LocalDefId,
|
||||||
decl: &hir::FnDecl<'_>,
|
decl: &hir::FnDecl<'_>,
|
||||||
body: &hir::Body<'_>,
|
closure_kind: hir::ClosureKind,
|
||||||
expected_sig: Option<ExpectedSig<'tcx>>,
|
expected_sig: Option<ExpectedSig<'tcx>>,
|
||||||
) -> ClosureSignatures<'tcx> {
|
) -> ClosureSignatures<'tcx> {
|
||||||
if let Some(e) = expected_sig {
|
if let Some(e) = expected_sig {
|
||||||
self.sig_of_closure_with_expectation(expr_def_id, decl, body, e)
|
self.sig_of_closure_with_expectation(expr_def_id, decl, closure_kind, e)
|
||||||
} else {
|
} else {
|
||||||
self.sig_of_closure_no_expectation(expr_def_id, decl, body)
|
self.sig_of_closure_no_expectation(expr_def_id, decl, closure_kind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If there is no expected signature, then we will convert the
|
/// If there is no expected signature, then we will convert the
|
||||||
/// types that the user gave into a signature.
|
/// types that the user gave into a signature.
|
||||||
#[instrument(skip(self, expr_def_id, decl, body), level = "debug")]
|
#[instrument(skip(self, expr_def_id, decl), level = "debug")]
|
||||||
fn sig_of_closure_no_expectation(
|
fn sig_of_closure_no_expectation(
|
||||||
&self,
|
&self,
|
||||||
expr_def_id: LocalDefId,
|
expr_def_id: LocalDefId,
|
||||||
decl: &hir::FnDecl<'_>,
|
decl: &hir::FnDecl<'_>,
|
||||||
body: &hir::Body<'_>,
|
closure_kind: hir::ClosureKind,
|
||||||
) -> ClosureSignatures<'tcx> {
|
) -> ClosureSignatures<'tcx> {
|
||||||
let bound_sig = self.supplied_sig_of_closure(expr_def_id, decl, body);
|
let bound_sig = self.supplied_sig_of_closure(expr_def_id, decl, closure_kind);
|
||||||
|
|
||||||
self.closure_sigs(expr_def_id, body, bound_sig)
|
self.closure_sigs(expr_def_id, bound_sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked to compute the signature of a closure expression. This
|
/// Invoked to compute the signature of a closure expression. This
|
||||||
@ -422,24 +423,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
/// - `expected_sig`: the expected signature (if any). Note that
|
/// - `expected_sig`: the expected signature (if any). Note that
|
||||||
/// this is missing a binder: that is, there may be late-bound
|
/// this is missing a binder: that is, there may be late-bound
|
||||||
/// regions with depth 1, which are bound then by the closure.
|
/// regions with depth 1, which are bound then by the closure.
|
||||||
#[instrument(skip(self, expr_def_id, decl, body), level = "debug")]
|
#[instrument(skip(self, expr_def_id, decl), level = "debug")]
|
||||||
fn sig_of_closure_with_expectation(
|
fn sig_of_closure_with_expectation(
|
||||||
&self,
|
&self,
|
||||||
expr_def_id: LocalDefId,
|
expr_def_id: LocalDefId,
|
||||||
decl: &hir::FnDecl<'_>,
|
decl: &hir::FnDecl<'_>,
|
||||||
body: &hir::Body<'_>,
|
closure_kind: hir::ClosureKind,
|
||||||
expected_sig: ExpectedSig<'tcx>,
|
expected_sig: ExpectedSig<'tcx>,
|
||||||
) -> ClosureSignatures<'tcx> {
|
) -> ClosureSignatures<'tcx> {
|
||||||
// Watch out for some surprises and just ignore the
|
// Watch out for some surprises and just ignore the
|
||||||
// expectation if things don't see to match up with what we
|
// expectation if things don't see to match up with what we
|
||||||
// expect.
|
// expect.
|
||||||
if expected_sig.sig.c_variadic() != decl.c_variadic {
|
if expected_sig.sig.c_variadic() != decl.c_variadic {
|
||||||
return self.sig_of_closure_no_expectation(expr_def_id, decl, body);
|
return self.sig_of_closure_no_expectation(expr_def_id, decl, closure_kind);
|
||||||
} else if expected_sig.sig.skip_binder().inputs_and_output.len() != decl.inputs.len() + 1 {
|
} else if expected_sig.sig.skip_binder().inputs_and_output.len() != decl.inputs.len() + 1 {
|
||||||
return self.sig_of_closure_with_mismatched_number_of_arguments(
|
return self.sig_of_closure_with_mismatched_number_of_arguments(
|
||||||
expr_def_id,
|
expr_def_id,
|
||||||
decl,
|
decl,
|
||||||
body,
|
|
||||||
expected_sig,
|
expected_sig,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -463,16 +463,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// anonymize away, so as not to confuse the user.
|
// anonymize away, so as not to confuse the user.
|
||||||
let bound_sig = self.tcx.anonymize_bound_vars(bound_sig);
|
let bound_sig = self.tcx.anonymize_bound_vars(bound_sig);
|
||||||
|
|
||||||
let closure_sigs = self.closure_sigs(expr_def_id, body, bound_sig);
|
let closure_sigs = self.closure_sigs(expr_def_id, bound_sig);
|
||||||
|
|
||||||
// Up till this point, we have ignored the annotations that the user
|
// Up till this point, we have ignored the annotations that the user
|
||||||
// gave. This function will check that they unify successfully.
|
// gave. This function will check that they unify successfully.
|
||||||
// Along the way, it also writes out entries for types that the user
|
// Along the way, it also writes out entries for types that the user
|
||||||
// wrote into our typeck results, which are then later used by the privacy
|
// wrote into our typeck results, which are then later used by the privacy
|
||||||
// check.
|
// check.
|
||||||
match self.merge_supplied_sig_with_expectation(expr_def_id, decl, body, closure_sigs) {
|
match self.merge_supplied_sig_with_expectation(
|
||||||
|
expr_def_id,
|
||||||
|
decl,
|
||||||
|
closure_kind,
|
||||||
|
closure_sigs,
|
||||||
|
) {
|
||||||
Ok(infer_ok) => self.register_infer_ok_obligations(infer_ok),
|
Ok(infer_ok) => self.register_infer_ok_obligations(infer_ok),
|
||||||
Err(_) => self.sig_of_closure_no_expectation(expr_def_id, decl, body),
|
Err(_) => self.sig_of_closure_no_expectation(expr_def_id, decl, closure_kind),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,7 +485,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
&self,
|
&self,
|
||||||
expr_def_id: LocalDefId,
|
expr_def_id: LocalDefId,
|
||||||
decl: &hir::FnDecl<'_>,
|
decl: &hir::FnDecl<'_>,
|
||||||
body: &hir::Body<'_>,
|
|
||||||
expected_sig: ExpectedSig<'tcx>,
|
expected_sig: ExpectedSig<'tcx>,
|
||||||
) -> ClosureSignatures<'tcx> {
|
) -> ClosureSignatures<'tcx> {
|
||||||
let expr_map_node = self.tcx.hir_node_by_def_id(expr_def_id);
|
let expr_map_node = self.tcx.hir_node_by_def_id(expr_def_id);
|
||||||
@ -511,25 +515,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
let error_sig = self.error_sig_of_closure(decl, guar);
|
let error_sig = self.error_sig_of_closure(decl, guar);
|
||||||
|
|
||||||
self.closure_sigs(expr_def_id, body, error_sig)
|
self.closure_sigs(expr_def_id, error_sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enforce the user's types against the expectation. See
|
/// Enforce the user's types against the expectation. See
|
||||||
/// `sig_of_closure_with_expectation` for details on the overall
|
/// `sig_of_closure_with_expectation` for details on the overall
|
||||||
/// strategy.
|
/// strategy.
|
||||||
#[instrument(level = "debug", skip(self, expr_def_id, decl, body, expected_sigs))]
|
#[instrument(level = "debug", skip(self, expr_def_id, decl, expected_sigs))]
|
||||||
fn merge_supplied_sig_with_expectation(
|
fn merge_supplied_sig_with_expectation(
|
||||||
&self,
|
&self,
|
||||||
expr_def_id: LocalDefId,
|
expr_def_id: LocalDefId,
|
||||||
decl: &hir::FnDecl<'_>,
|
decl: &hir::FnDecl<'_>,
|
||||||
body: &hir::Body<'_>,
|
closure_kind: hir::ClosureKind,
|
||||||
mut expected_sigs: ClosureSignatures<'tcx>,
|
mut expected_sigs: ClosureSignatures<'tcx>,
|
||||||
) -> InferResult<'tcx, ClosureSignatures<'tcx>> {
|
) -> InferResult<'tcx, ClosureSignatures<'tcx>> {
|
||||||
// Get the signature S that the user gave.
|
// Get the signature S that the user gave.
|
||||||
//
|
//
|
||||||
// (See comment on `sig_of_closure_with_expectation` for the
|
// (See comment on `sig_of_closure_with_expectation` for the
|
||||||
// meaning of these letters.)
|
// meaning of these letters.)
|
||||||
let supplied_sig = self.supplied_sig_of_closure(expr_def_id, decl, body);
|
let supplied_sig = self.supplied_sig_of_closure(expr_def_id, decl, closure_kind);
|
||||||
|
|
||||||
debug!(?supplied_sig);
|
debug!(?supplied_sig);
|
||||||
|
|
||||||
@ -611,17 +615,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
/// types that the user gave into a signature.
|
/// types that the user gave into a signature.
|
||||||
///
|
///
|
||||||
/// Also, record this closure signature for later.
|
/// Also, record this closure signature for later.
|
||||||
#[instrument(skip(self, decl, body), level = "debug", ret)]
|
#[instrument(skip(self, decl), level = "debug", ret)]
|
||||||
fn supplied_sig_of_closure(
|
fn supplied_sig_of_closure(
|
||||||
&self,
|
&self,
|
||||||
expr_def_id: LocalDefId,
|
expr_def_id: LocalDefId,
|
||||||
decl: &hir::FnDecl<'_>,
|
decl: &hir::FnDecl<'_>,
|
||||||
body: &hir::Body<'_>,
|
closure_kind: hir::ClosureKind,
|
||||||
) -> ty::PolyFnSig<'tcx> {
|
) -> ty::PolyFnSig<'tcx> {
|
||||||
let astconv: &dyn AstConv<'_> = self;
|
let astconv: &dyn AstConv<'_> = self;
|
||||||
|
|
||||||
trace!("decl = {:#?}", decl);
|
trace!("decl = {:#?}", decl);
|
||||||
debug!(?body.coroutine_kind);
|
debug!(?closure_kind);
|
||||||
|
|
||||||
let hir_id = self.tcx.local_def_id_to_hir_id(expr_def_id);
|
let hir_id = self.tcx.local_def_id_to_hir_id(expr_def_id);
|
||||||
let bound_vars = self.tcx.late_bound_vars(hir_id);
|
let bound_vars = self.tcx.late_bound_vars(hir_id);
|
||||||
@ -630,18 +634,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let supplied_arguments = decl.inputs.iter().map(|a| astconv.ast_ty_to_ty(a));
|
let supplied_arguments = decl.inputs.iter().map(|a| astconv.ast_ty_to_ty(a));
|
||||||
let supplied_return = match decl.output {
|
let supplied_return = match decl.output {
|
||||||
hir::FnRetTy::Return(ref output) => astconv.ast_ty_to_ty(output),
|
hir::FnRetTy::Return(ref output) => astconv.ast_ty_to_ty(output),
|
||||||
hir::FnRetTy::DefaultReturn(_) => match body.coroutine_kind {
|
hir::FnRetTy::DefaultReturn(_) => match closure_kind {
|
||||||
// In the case of the async block that we create for a function body,
|
// In the case of the async block that we create for a function body,
|
||||||
// we expect the return type of the block to match that of the enclosing
|
// we expect the return type of the block to match that of the enclosing
|
||||||
// function.
|
// function.
|
||||||
Some(hir::CoroutineKind::Desugared(
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||||
hir::CoroutineDesugaring::Async,
|
hir::CoroutineDesugaring::Async,
|
||||||
hir::CoroutineSource::Fn,
|
hir::CoroutineSource::Fn,
|
||||||
)) => {
|
)) => {
|
||||||
debug!("closure is async fn body");
|
debug!("closure is async fn body");
|
||||||
let def_id = self.tcx.hir().body_owner_def_id(body.id());
|
self.deduce_future_output_from_obligations(expr_def_id).unwrap_or_else(|| {
|
||||||
self.deduce_future_output_from_obligations(expr_def_id, def_id).unwrap_or_else(
|
|
||||||
|| {
|
|
||||||
// AFAIK, deducing the future output
|
// AFAIK, deducing the future output
|
||||||
// always succeeds *except* in error cases
|
// always succeeds *except* in error cases
|
||||||
// like #65159. I'd like to return Error
|
// like #65159. I'd like to return Error
|
||||||
@ -650,16 +652,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// *have* reported an
|
// *have* reported an
|
||||||
// error. --nikomatsakis
|
// error. --nikomatsakis
|
||||||
astconv.ty_infer(None, decl.output.span())
|
astconv.ty_infer(None, decl.output.span())
|
||||||
},
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
// All `gen {}` and `async gen {}` must return unit.
|
// All `gen {}` and `async gen {}` must return unit.
|
||||||
Some(
|
hir::ClosureKind::Coroutine(
|
||||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
|
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
|
||||||
| hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _),
|
| hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _),
|
||||||
) => self.tcx.types.unit,
|
) => self.tcx.types.unit,
|
||||||
|
|
||||||
_ => astconv.ty_infer(None, decl.output.span()),
|
// For async blocks, we just fall back to `_` here.
|
||||||
|
// For closures/coroutines, we know nothing about the return
|
||||||
|
// type unless it was supplied.
|
||||||
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||||
|
hir::CoroutineDesugaring::Async,
|
||||||
|
_,
|
||||||
|
))
|
||||||
|
| hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_))
|
||||||
|
| hir::ClosureKind::Closure => astconv.ty_infer(None, decl.output.span()),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -688,16 +697,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
/// Future<Output = T>`, so we do this by searching through the
|
/// Future<Output = T>`, so we do this by searching through the
|
||||||
/// obligations to extract the `T`.
|
/// obligations to extract the `T`.
|
||||||
#[instrument(skip(self), level = "debug", ret)]
|
#[instrument(skip(self), level = "debug", ret)]
|
||||||
fn deduce_future_output_from_obligations(
|
fn deduce_future_output_from_obligations(&self, body_def_id: LocalDefId) -> Option<Ty<'tcx>> {
|
||||||
&self,
|
|
||||||
expr_def_id: LocalDefId,
|
|
||||||
body_def_id: LocalDefId,
|
|
||||||
) -> Option<Ty<'tcx>> {
|
|
||||||
let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| {
|
let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| {
|
||||||
span_bug!(self.tcx.def_span(expr_def_id), "async fn coroutine outside of a fn")
|
span_bug!(self.tcx.def_span(body_def_id), "async fn coroutine outside of a fn")
|
||||||
});
|
});
|
||||||
|
|
||||||
let closure_span = self.tcx.def_span(expr_def_id);
|
let closure_span = self.tcx.def_span(body_def_id);
|
||||||
let ret_ty = ret_coercion.borrow().expected_ty();
|
let ret_ty = ret_coercion.borrow().expected_ty();
|
||||||
let ret_ty = self.try_structurally_resolve_type(closure_span, ret_ty);
|
let ret_ty = self.try_structurally_resolve_type(closure_span, ret_ty);
|
||||||
|
|
||||||
@ -842,12 +847,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
fn closure_sigs(
|
fn closure_sigs(
|
||||||
&self,
|
&self,
|
||||||
expr_def_id: LocalDefId,
|
expr_def_id: LocalDefId,
|
||||||
body: &hir::Body<'_>,
|
|
||||||
bound_sig: ty::PolyFnSig<'tcx>,
|
bound_sig: ty::PolyFnSig<'tcx>,
|
||||||
) -> ClosureSignatures<'tcx> {
|
) -> ClosureSignatures<'tcx> {
|
||||||
let liberated_sig =
|
let liberated_sig =
|
||||||
self.tcx().liberate_late_bound_regions(expr_def_id.to_def_id(), bound_sig);
|
self.tcx().liberate_late_bound_regions(expr_def_id.to_def_id(), bound_sig);
|
||||||
let liberated_sig = self.normalize(body.value.span, liberated_sig);
|
let liberated_sig = self.normalize(self.tcx.def_span(expr_def_id), liberated_sig);
|
||||||
ClosureSignatures { bound_sig, liberated_sig }
|
ClosureSignatures { bound_sig, liberated_sig }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,7 +199,8 @@ fixed_size_enum! {
|
|||||||
|
|
||||||
fixed_size_enum! {
|
fixed_size_enum! {
|
||||||
hir::CoroutineKind {
|
hir::CoroutineKind {
|
||||||
( Coroutine )
|
( Coroutine(hir::Movability::Movable) )
|
||||||
|
( Coroutine(hir::Movability::Static) )
|
||||||
( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Block) )
|
( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Block) )
|
||||||
( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Fn) )
|
( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Fn) )
|
||||||
( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Closure) )
|
( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Closure) )
|
||||||
|
@ -307,11 +307,6 @@ pub struct ScopeTree {
|
|||||||
/// the values are still owned by their containing expressions. So
|
/// the values are still owned by their containing expressions. So
|
||||||
/// we'll see that `&x`.
|
/// we'll see that `&x`.
|
||||||
pub yield_in_scope: FxHashMap<Scope, Vec<YieldData>>,
|
pub yield_in_scope: FxHashMap<Scope, Vec<YieldData>>,
|
||||||
|
|
||||||
/// The number of visit_expr and visit_pat calls done in the body.
|
|
||||||
/// Used to sanity check visit_expr/visit_pat call count when
|
|
||||||
/// calculating coroutine interiors.
|
|
||||||
pub body_expr_count: FxHashMap<hir::BodyId, usize>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Identifies the reason that a given expression is an rvalue candidate
|
/// Identifies the reason that a given expression is an rvalue candidate
|
||||||
@ -408,20 +403,12 @@ impl ScopeTree {
|
|||||||
pub fn yield_in_scope(&self, scope: Scope) -> Option<&[YieldData]> {
|
pub fn yield_in_scope(&self, scope: Scope) -> Option<&[YieldData]> {
|
||||||
self.yield_in_scope.get(&scope).map(Deref::deref)
|
self.yield_in_scope.get(&scope).map(Deref::deref)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gives the number of expressions visited in a body.
|
|
||||||
/// Used to sanity check visit_expr call count when
|
|
||||||
/// calculating coroutine interiors.
|
|
||||||
pub fn body_expr_count(&self, body_id: hir::BodyId) -> Option<usize> {
|
|
||||||
self.body_expr_count.get(&body_id).copied()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree {
|
impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree {
|
||||||
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
|
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
|
||||||
let ScopeTree {
|
let ScopeTree {
|
||||||
root_body,
|
root_body,
|
||||||
ref body_expr_count,
|
|
||||||
ref parent_map,
|
ref parent_map,
|
||||||
ref var_map,
|
ref var_map,
|
||||||
ref destruction_scopes,
|
ref destruction_scopes,
|
||||||
@ -430,7 +417,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree {
|
|||||||
} = *self;
|
} = *self;
|
||||||
|
|
||||||
root_body.hash_stable(hcx, hasher);
|
root_body.hash_stable(hcx, hasher);
|
||||||
body_expr_count.hash_stable(hcx, hasher);
|
|
||||||
parent_map.hash_stable(hcx, hasher);
|
parent_map.hash_stable(hcx, hasher);
|
||||||
var_map.hash_stable(hcx, hasher);
|
var_map.hash_stable(hcx, hasher);
|
||||||
destruction_scopes.hash_stable(hcx, hasher);
|
destruction_scopes.hash_stable(hcx, hasher);
|
||||||
|
@ -147,7 +147,7 @@ impl<O> AssertKind<O> {
|
|||||||
Overflow(op, _, _) => bug!("{:?} cannot overflow", op),
|
Overflow(op, _, _) => bug!("{:?} cannot overflow", op),
|
||||||
DivisionByZero(_) => "attempt to divide by zero",
|
DivisionByZero(_) => "attempt to divide by zero",
|
||||||
RemainderByZero(_) => "attempt to calculate the remainder with a divisor of zero",
|
RemainderByZero(_) => "attempt to calculate the remainder with a divisor of zero",
|
||||||
ResumedAfterReturn(CoroutineKind::Coroutine) => "coroutine resumed after completion",
|
ResumedAfterReturn(CoroutineKind::Coroutine(_)) => "coroutine resumed after completion",
|
||||||
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
|
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
|
||||||
"`async fn` resumed after completion"
|
"`async fn` resumed after completion"
|
||||||
}
|
}
|
||||||
@ -157,7 +157,7 @@ impl<O> AssertKind<O> {
|
|||||||
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
|
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
|
||||||
"`gen fn` should just keep returning `None` after completion"
|
"`gen fn` should just keep returning `None` after completion"
|
||||||
}
|
}
|
||||||
ResumedAfterPanic(CoroutineKind::Coroutine) => "coroutine resumed after panicking",
|
ResumedAfterPanic(CoroutineKind::Coroutine(_)) => "coroutine resumed after panicking",
|
||||||
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
|
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
|
||||||
"`async fn` resumed after panicking"
|
"`async fn` resumed after panicking"
|
||||||
}
|
}
|
||||||
@ -262,7 +262,7 @@ impl<O> AssertKind<O> {
|
|||||||
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
|
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
|
||||||
bug!("gen blocks can be resumed after they return and will keep returning `None`")
|
bug!("gen blocks can be resumed after they return and will keep returning `None`")
|
||||||
}
|
}
|
||||||
ResumedAfterReturn(CoroutineKind::Coroutine) => {
|
ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
|
||||||
middle_assert_coroutine_resume_after_return
|
middle_assert_coroutine_resume_after_return
|
||||||
}
|
}
|
||||||
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
|
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
|
||||||
@ -274,7 +274,7 @@ impl<O> AssertKind<O> {
|
|||||||
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
|
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
|
||||||
middle_assert_gen_resume_after_panic
|
middle_assert_gen_resume_after_panic
|
||||||
}
|
}
|
||||||
ResumedAfterPanic(CoroutineKind::Coroutine) => {
|
ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
|
||||||
middle_assert_coroutine_resume_after_panic
|
middle_assert_coroutine_resume_after_panic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -858,7 +858,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
/// Returns `true` if the node pointed to by `def_id` is a general coroutine that implements `Coroutine`.
|
/// Returns `true` if the node pointed to by `def_id` is a general coroutine that implements `Coroutine`.
|
||||||
/// This means it is neither an `async` or `gen` construct.
|
/// This means it is neither an `async` or `gen` construct.
|
||||||
pub fn is_general_coroutine(self, def_id: DefId) -> bool {
|
pub fn is_general_coroutine(self, def_id: DefId) -> bool {
|
||||||
matches!(self.coroutine_kind(def_id), Some(hir::CoroutineKind::Coroutine))
|
matches!(self.coroutine_kind(def_id), Some(hir::CoroutineKind::Coroutine(_)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the node pointed to by `def_id` is a coroutine for a `gen` construct.
|
/// Returns `true` if the node pointed to by `def_id` is a coroutine for a `gen` construct.
|
||||||
|
@ -786,8 +786,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||||||
ty::Coroutine(did, args, movability) => {
|
ty::Coroutine(did, args, movability) => {
|
||||||
p!(write("{{"));
|
p!(write("{{"));
|
||||||
let coroutine_kind = self.tcx().coroutine_kind(did).unwrap();
|
let coroutine_kind = self.tcx().coroutine_kind(did).unwrap();
|
||||||
let should_print_movability =
|
let should_print_movability = self.should_print_verbose()
|
||||||
self.should_print_verbose() || coroutine_kind == hir::CoroutineKind::Coroutine;
|
|| matches!(coroutine_kind, hir::CoroutineKind::Coroutine(_));
|
||||||
|
|
||||||
if should_print_movability {
|
if should_print_movability {
|
||||||
match movability {
|
match movability {
|
||||||
|
@ -735,7 +735,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => {
|
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => {
|
||||||
"async gen closure"
|
"async gen closure"
|
||||||
}
|
}
|
||||||
hir::CoroutineKind::Coroutine => "coroutine",
|
hir::CoroutineKind::Coroutine(_) => "coroutine",
|
||||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) => {
|
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) => {
|
||||||
"gen closure"
|
"gen closure"
|
||||||
}
|
}
|
||||||
@ -759,7 +759,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, ..) => "an",
|
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, ..) => "an",
|
||||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, ..) => "an",
|
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, ..) => "an",
|
||||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, ..) => "a",
|
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, ..) => "a",
|
||||||
hir::CoroutineKind::Coroutine => "a",
|
hir::CoroutineKind::Coroutine(_) => "a",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => def_kind.article(),
|
_ => def_kind.article(),
|
||||||
|
@ -257,7 +257,7 @@ impl<'tcx> TransformVisitor<'tcx> {
|
|||||||
CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => {
|
CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => {
|
||||||
span_bug!(body.span, "`Future`s are not fused inherently")
|
span_bug!(body.span, "`Future`s are not fused inherently")
|
||||||
}
|
}
|
||||||
CoroutineKind::Coroutine => span_bug!(body.span, "`Coroutine`s cannot be fused"),
|
CoroutineKind::Coroutine(_) => span_bug!(body.span, "`Coroutine`s cannot be fused"),
|
||||||
// `gen` continues return `None`
|
// `gen` continues return `None`
|
||||||
CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {
|
CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {
|
||||||
let option_def_id = self.tcx.require_lang_item(LangItem::Option, None);
|
let option_def_id = self.tcx.require_lang_item(LangItem::Option, None);
|
||||||
@ -396,7 +396,7 @@ impl<'tcx> TransformVisitor<'tcx> {
|
|||||||
Rvalue::Use(val)
|
Rvalue::Use(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CoroutineKind::Coroutine => {
|
CoroutineKind::Coroutine(_) => {
|
||||||
let coroutine_state_def_id =
|
let coroutine_state_def_id =
|
||||||
self.tcx.require_lang_item(LangItem::CoroutineState, None);
|
self.tcx.require_lang_item(LangItem::CoroutineState, None);
|
||||||
let args = self.tcx.mk_args(&[self.old_yield_ty.into(), self.old_ret_ty.into()]);
|
let args = self.tcx.mk_args(&[self.old_yield_ty.into(), self.old_ret_ty.into()]);
|
||||||
@ -1428,7 +1428,8 @@ fn create_coroutine_resume_function<'tcx>(
|
|||||||
|
|
||||||
if can_return {
|
if can_return {
|
||||||
let block = match coroutine_kind {
|
let block = match coroutine_kind {
|
||||||
CoroutineKind::Desugared(CoroutineDesugaring::Async, _) | CoroutineKind::Coroutine => {
|
CoroutineKind::Desugared(CoroutineDesugaring::Async, _)
|
||||||
|
| CoroutineKind::Coroutine(_) => {
|
||||||
insert_panic_block(tcx, body, ResumedAfterReturn(coroutine_kind))
|
insert_panic_block(tcx, body, ResumedAfterReturn(coroutine_kind))
|
||||||
}
|
}
|
||||||
CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)
|
CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)
|
||||||
@ -1643,7 +1644,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
|
|||||||
// The yield ty is already `Poll<Option<yield_ty>>`
|
// The yield ty is already `Poll<Option<yield_ty>>`
|
||||||
old_yield_ty
|
old_yield_ty
|
||||||
}
|
}
|
||||||
CoroutineKind::Coroutine => {
|
CoroutineKind::Coroutine(_) => {
|
||||||
// Compute CoroutineState<yield_ty, return_ty>
|
// Compute CoroutineState<yield_ty, return_ty>
|
||||||
let state_did = tcx.require_lang_item(LangItem::CoroutineState, None);
|
let state_did = tcx.require_lang_item(LangItem::CoroutineState, None);
|
||||||
let state_adt_ref = tcx.adt_def(state_did);
|
let state_adt_ref = tcx.adt_def(state_did);
|
||||||
|
@ -3,7 +3,7 @@ use Context::*;
|
|||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{LocalDefId, LocalModDefId};
|
use rustc_hir::def_id::{LocalDefId, LocalModDefId};
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::{Destination, Movability, Node};
|
use rustc_hir::{Destination, Node};
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
@ -86,16 +86,15 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
|||||||
self.with_context(Loop(source), |v| v.visit_block(b));
|
self.with_context(Loop(source), |v| v.visit_block(b));
|
||||||
}
|
}
|
||||||
hir::ExprKind::Closure(&hir::Closure {
|
hir::ExprKind::Closure(&hir::Closure {
|
||||||
ref fn_decl,
|
ref fn_decl, body, fn_decl_span, kind, ..
|
||||||
body,
|
|
||||||
fn_decl_span,
|
|
||||||
movability,
|
|
||||||
..
|
|
||||||
}) => {
|
}) => {
|
||||||
let cx = if let Some(Movability::Static) = movability {
|
// FIXME(coroutines): This doesn't handle coroutines correctly
|
||||||
AsyncClosure(fn_decl_span)
|
let cx = match kind {
|
||||||
} else {
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||||
Closure(fn_decl_span)
|
hir::CoroutineDesugaring::Async,
|
||||||
|
hir::CoroutineSource::Block,
|
||||||
|
)) => AsyncClosure(fn_decl_span),
|
||||||
|
_ => Closure(fn_decl_span),
|
||||||
};
|
};
|
||||||
self.visit_fn_decl(fn_decl);
|
self.visit_fn_decl(fn_decl);
|
||||||
self.with_context(cx, |v| v.visit_nested_body(body));
|
self.with_context(cx, |v| v.visit_nested_body(body));
|
||||||
|
@ -42,7 +42,7 @@ impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind {
|
|||||||
type T = stable_mir::mir::CoroutineKind;
|
type T = stable_mir::mir::CoroutineKind;
|
||||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
use rustc_hir::{CoroutineDesugaring, CoroutineKind};
|
use rustc_hir::{CoroutineDesugaring, CoroutineKind};
|
||||||
match self {
|
match *self {
|
||||||
CoroutineKind::Desugared(CoroutineDesugaring::Async, source) => {
|
CoroutineKind::Desugared(CoroutineDesugaring::Async, source) => {
|
||||||
stable_mir::mir::CoroutineKind::Desugared(
|
stable_mir::mir::CoroutineKind::Desugared(
|
||||||
stable_mir::mir::CoroutineDesugaring::Async,
|
stable_mir::mir::CoroutineDesugaring::Async,
|
||||||
@ -55,7 +55,9 @@ impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind {
|
|||||||
source.stable(tables),
|
source.stable(tables),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
CoroutineKind::Coroutine => stable_mir::mir::CoroutineKind::Coroutine,
|
CoroutineKind::Coroutine(movability) => {
|
||||||
|
stable_mir::mir::CoroutineKind::Coroutine(movability.stable(tables))
|
||||||
|
}
|
||||||
CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, source) => {
|
CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, source) => {
|
||||||
stable_mir::mir::CoroutineKind::Desugared(
|
stable_mir::mir::CoroutineKind::Desugared(
|
||||||
stable_mir::mir::CoroutineDesugaring::AsyncGen,
|
stable_mir::mir::CoroutineDesugaring::AsyncGen,
|
||||||
|
@ -8,7 +8,7 @@ use rustc_attr as attr;
|
|||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_errors::{struct_span_err, ErrorGuaranteed};
|
use rustc_errors::{struct_span_err, ErrorGuaranteed};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_middle::ty::GenericArgsRef;
|
use rustc_middle::ty::GenericArgsRef;
|
||||||
use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
|
use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
|
||||||
use rustc_parse_format::{ParseMode, Parser, Piece, Position};
|
use rustc_parse_format::{ParseMode, Parser, Piece, Position};
|
||||||
@ -32,7 +32,7 @@ pub trait TypeErrCtxtExt<'tcx> {
|
|||||||
) -> Option<(DefId, GenericArgsRef<'tcx>)>;
|
) -> Option<(DefId, GenericArgsRef<'tcx>)>;
|
||||||
|
|
||||||
/*private*/
|
/*private*/
|
||||||
fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str>;
|
fn describe_enclosure(&self, def_id: LocalDefId) -> Option<&'static str>;
|
||||||
|
|
||||||
fn on_unimplemented_note(
|
fn on_unimplemented_note(
|
||||||
&self,
|
&self,
|
||||||
@ -101,43 +101,19 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||||||
|
|
||||||
/// Used to set on_unimplemented's `ItemContext`
|
/// Used to set on_unimplemented's `ItemContext`
|
||||||
/// to be the enclosing (async) block/function/closure
|
/// to be the enclosing (async) block/function/closure
|
||||||
fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
|
fn describe_enclosure(&self, def_id: LocalDefId) -> Option<&'static str> {
|
||||||
let hir = self.tcx.hir();
|
match self.tcx.opt_hir_node_by_def_id(def_id)? {
|
||||||
let node = self.tcx.opt_hir_node(hir_id)?;
|
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }) => Some("a function"),
|
||||||
match &node {
|
hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) => {
|
||||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => {
|
Some("a trait method")
|
||||||
self.describe_coroutine(*body_id).or_else(|| {
|
|
||||||
Some(match sig.header {
|
|
||||||
hir::FnHeader { asyncness: hir::IsAsync::Async(_), .. } => {
|
|
||||||
"an async function"
|
|
||||||
}
|
}
|
||||||
_ => "a function",
|
hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => {
|
||||||
})
|
Some("a method")
|
||||||
})
|
|
||||||
}
|
}
|
||||||
hir::Node::TraitItem(hir::TraitItem {
|
|
||||||
kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)),
|
|
||||||
..
|
|
||||||
}) => self.describe_coroutine(*body_id).or_else(|| Some("a trait method")),
|
|
||||||
hir::Node::ImplItem(hir::ImplItem {
|
|
||||||
kind: hir::ImplItemKind::Fn(sig, body_id),
|
|
||||||
..
|
|
||||||
}) => self.describe_coroutine(*body_id).or_else(|| {
|
|
||||||
Some(match sig.header {
|
|
||||||
hir::FnHeader { asyncness: hir::IsAsync::Async(_), .. } => "an async method",
|
|
||||||
_ => "a method",
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
hir::Node::Expr(hir::Expr {
|
hir::Node::Expr(hir::Expr {
|
||||||
kind: hir::ExprKind::Closure(hir::Closure { body, movability, .. }),
|
kind: hir::ExprKind::Closure(hir::Closure { kind, .. }),
|
||||||
..
|
..
|
||||||
}) => self.describe_coroutine(*body).or_else(|| {
|
}) => Some(self.describe_closure(*kind)),
|
||||||
Some(if movability.is_some() { "an async closure" } else { "a closure" })
|
|
||||||
}),
|
|
||||||
hir::Node::Expr(hir::Expr { .. }) => {
|
|
||||||
let parent_hid = hir.parent_id(hir_id);
|
|
||||||
if parent_hid != hir_id { self.describe_enclosure(parent_hid) } else { None }
|
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,12 +132,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||||||
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs,
|
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs,
|
||||||
// but I guess we could synthesize one here. We don't see any errors that rely on
|
// but I guess we could synthesize one here. We don't see any errors that rely on
|
||||||
// that yet, though.
|
// that yet, though.
|
||||||
let enclosure =
|
let enclosure = self.describe_enclosure(obligation.cause.body_id).map(|t| t.to_owned());
|
||||||
if let Some(body_hir) = self.tcx.opt_local_def_id_to_hir_id(obligation.cause.body_id) {
|
|
||||||
self.describe_enclosure(body_hir).map(|s| s.to_owned())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
flags.push((sym::ItemContext, enclosure));
|
flags.push((sym::ItemContext, enclosure));
|
||||||
|
|
||||||
match obligation.cause.code() {
|
match obligation.cause.code() {
|
||||||
|
@ -2577,7 +2577,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||||||
let message = outer_coroutine
|
let message = outer_coroutine
|
||||||
.and_then(|coroutine_did| {
|
.and_then(|coroutine_did| {
|
||||||
Some(match self.tcx.coroutine_kind(coroutine_did).unwrap() {
|
Some(match self.tcx.coroutine_kind(coroutine_did).unwrap() {
|
||||||
CoroutineKind::Coroutine => format!("coroutine is not {trait_name}"),
|
CoroutineKind::Coroutine(_) => format!("coroutine is not {trait_name}"),
|
||||||
CoroutineKind::Desugared(
|
CoroutineKind::Desugared(
|
||||||
CoroutineDesugaring::Async,
|
CoroutineDesugaring::Async,
|
||||||
CoroutineSource::Fn,
|
CoroutineSource::Fn,
|
||||||
@ -3169,7 +3169,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||||||
ObligationCauseCode::SizedCoroutineInterior(coroutine_def_id) => {
|
ObligationCauseCode::SizedCoroutineInterior(coroutine_def_id) => {
|
||||||
let what = match self.tcx.coroutine_kind(coroutine_def_id) {
|
let what = match self.tcx.coroutine_kind(coroutine_def_id) {
|
||||||
None
|
None
|
||||||
| Some(hir::CoroutineKind::Coroutine)
|
| Some(hir::CoroutineKind::Coroutine(_))
|
||||||
| Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => {
|
| Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => {
|
||||||
"yield"
|
"yield"
|
||||||
}
|
}
|
||||||
@ -3564,10 +3564,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) {
|
) {
|
||||||
if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) {
|
|
||||||
let body = self.tcx.hir().body(body_id);
|
|
||||||
if let Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) =
|
if let Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) =
|
||||||
body.coroutine_kind
|
self.tcx.coroutine_kind(obligation.cause.body_id)
|
||||||
{
|
{
|
||||||
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
||||||
|
|
||||||
@ -3615,7 +3613,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn suggest_floating_point_literal(
|
fn suggest_floating_point_literal(
|
||||||
&self,
|
&self,
|
||||||
@ -4665,13 +4662,7 @@ impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
|
|||||||
|
|
||||||
fn visit_body(&mut self, body: &'v hir::Body<'v>) {
|
fn visit_body(&mut self, body: &'v hir::Body<'v>) {
|
||||||
assert!(!self.in_block_tail);
|
assert!(!self.in_block_tail);
|
||||||
if body.coroutine_kind().is_none() {
|
|
||||||
if let hir::ExprKind::Block(block, None) = body.value.kind {
|
|
||||||
if block.expr.is_some() {
|
|
||||||
self.in_block_tail = true;
|
self.in_block_tail = true;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hir::intravisit::walk_body(self, body);
|
hir::intravisit::walk_body(self, body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1348,7 +1348,7 @@ pub(super) trait InferCtxtPrivExt<'tcx> {
|
|||||||
ignoring_lifetimes: bool,
|
ignoring_lifetimes: bool,
|
||||||
) -> Option<CandidateSimilarity>;
|
) -> Option<CandidateSimilarity>;
|
||||||
|
|
||||||
fn describe_coroutine(&self, body_id: hir::BodyId) -> Option<&'static str>;
|
fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str;
|
||||||
|
|
||||||
fn find_similar_impl_candidates(
|
fn find_similar_impl_candidates(
|
||||||
&self,
|
&self,
|
||||||
@ -1925,9 +1925,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn describe_coroutine(&self, body_id: hir::BodyId) -> Option<&'static str> {
|
fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str {
|
||||||
self.tcx.hir().body(body_id).coroutine_kind.map(|coroutine_source| match coroutine_source {
|
match kind {
|
||||||
hir::CoroutineKind::Coroutine => "a coroutine",
|
hir::ClosureKind::Closure => "a closure",
|
||||||
|
hir::ClosureKind::Coroutine(kind) => match kind {
|
||||||
|
hir::CoroutineKind::Coroutine(_) => "a coroutine",
|
||||||
hir::CoroutineKind::Desugared(
|
hir::CoroutineKind::Desugared(
|
||||||
hir::CoroutineDesugaring::Async,
|
hir::CoroutineDesugaring::Async,
|
||||||
hir::CoroutineSource::Block,
|
hir::CoroutineSource::Block,
|
||||||
@ -1964,7 +1966,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||||||
hir::CoroutineDesugaring::Gen,
|
hir::CoroutineDesugaring::Gen,
|
||||||
hir::CoroutineSource::Closure,
|
hir::CoroutineSource::Closure,
|
||||||
) => "a gen closure",
|
) => "a gen closure",
|
||||||
})
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_similar_impl_candidates(
|
fn find_similar_impl_candidates(
|
||||||
|
@ -121,7 +121,7 @@ fn fn_sig_for_fn_abi<'tcx>(
|
|||||||
}
|
}
|
||||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)
|
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)
|
||||||
| hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)
|
| hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)
|
||||||
| hir::CoroutineKind::Coroutine => Ty::new_adt(tcx, pin_adt_ref, pin_args),
|
| hir::CoroutineKind::Coroutine(_) => Ty::new_adt(tcx, pin_adt_ref, pin_args),
|
||||||
};
|
};
|
||||||
|
|
||||||
// The `FnSig` and the `ret_ty` here is for a coroutines main
|
// The `FnSig` and the `ret_ty` here is for a coroutines main
|
||||||
@ -192,7 +192,7 @@ fn fn_sig_for_fn_abi<'tcx>(
|
|||||||
|
|
||||||
(Some(context_mut_ref), ret_ty)
|
(Some(context_mut_ref), ret_ty)
|
||||||
}
|
}
|
||||||
hir::CoroutineKind::Coroutine => {
|
hir::CoroutineKind::Coroutine(_) => {
|
||||||
// The signature should be `Coroutine::resume(_, Resume) -> CoroutineState<Yield, Return>`
|
// The signature should be `Coroutine::resume(_, Resume) -> CoroutineState<Yield, Return>`
|
||||||
let state_did = tcx.require_lang_item(LangItem::CoroutineState, None);
|
let state_did = tcx.require_lang_item(LangItem::CoroutineState, None);
|
||||||
let state_adt_ref = tcx.adt_def(state_did);
|
let state_adt_ref = tcx.adt_def(state_did);
|
||||||
|
@ -285,7 +285,7 @@ impl AssertMessage {
|
|||||||
AssertMessage::RemainderByZero(_) => {
|
AssertMessage::RemainderByZero(_) => {
|
||||||
Ok("attempt to calculate the remainder with a divisor of zero")
|
Ok("attempt to calculate the remainder with a divisor of zero")
|
||||||
}
|
}
|
||||||
AssertMessage::ResumedAfterReturn(CoroutineKind::Coroutine) => {
|
AssertMessage::ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
|
||||||
Ok("coroutine resumed after completion")
|
Ok("coroutine resumed after completion")
|
||||||
}
|
}
|
||||||
AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
|
AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
|
||||||
@ -300,7 +300,7 @@ impl AssertMessage {
|
|||||||
CoroutineDesugaring::AsyncGen,
|
CoroutineDesugaring::AsyncGen,
|
||||||
_,
|
_,
|
||||||
)) => Ok("`gen fn` should just keep returning `AssertMessage::None` after completion"),
|
)) => Ok("`gen fn` should just keep returning `AssertMessage::None` after completion"),
|
||||||
AssertMessage::ResumedAfterPanic(CoroutineKind::Coroutine) => {
|
AssertMessage::ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
|
||||||
Ok("coroutine resumed after panicking")
|
Ok("coroutine resumed after panicking")
|
||||||
}
|
}
|
||||||
AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
|
AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
|
||||||
@ -399,7 +399,7 @@ pub enum UnOp {
|
|||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum CoroutineKind {
|
pub enum CoroutineKind {
|
||||||
Desugared(CoroutineDesugaring, CoroutineSource),
|
Desugared(CoroutineDesugaring, CoroutineSource),
|
||||||
Coroutine,
|
Coroutine(Movability),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
@ -2,7 +2,9 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
|
|||||||
use clippy_utils::source::snippet;
|
use clippy_utils::source::snippet;
|
||||||
use clippy_utils::ty::implements_trait;
|
use clippy_utils::ty::implements_trait;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Body, BodyId, CoroutineKind, CoroutineSource, CoroutineDesugaring, ExprKind, QPath};
|
use rustc_hir::{
|
||||||
|
Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, QPath,
|
||||||
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
|
|
||||||
@ -44,15 +46,22 @@ declare_clippy_lint! {
|
|||||||
declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]);
|
declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]);
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
|
impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
|
||||||
fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||||
// For functions, with explicitly defined types, don't warn.
|
// For functions, with explicitly defined types, don't warn.
|
||||||
// XXXkhuey maybe we should?
|
// XXXkhuey maybe we should?
|
||||||
if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block | CoroutineSource::Closure)) = body.coroutine_kind {
|
if let ExprKind::Closure(Closure {
|
||||||
|
kind:
|
||||||
|
ClosureKind::Coroutine(CoroutineKind::Desugared(
|
||||||
|
CoroutineDesugaring::Async,
|
||||||
|
CoroutineSource::Block | CoroutineSource::Closure,
|
||||||
|
)),
|
||||||
|
body: body_id,
|
||||||
|
..
|
||||||
|
}) = expr.kind
|
||||||
|
{
|
||||||
if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() {
|
if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() {
|
||||||
let body_id = BodyId {
|
let typeck_results = cx.tcx.typeck_body(*body_id);
|
||||||
hir_id: body.value.hir_id,
|
let body = cx.tcx.hir().body(*body_id);
|
||||||
};
|
|
||||||
let typeck_results = cx.tcx.typeck_body(body_id);
|
|
||||||
let expr_ty = typeck_results.expr_ty(body.value);
|
let expr_ty = typeck_results.expr_ty(body.value);
|
||||||
|
|
||||||
if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
|
if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
|
||||||
|
@ -2,8 +2,8 @@ use clippy_config::types::DisallowedPath;
|
|||||||
use clippy_utils::diagnostics::span_lint_and_then;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use clippy_utils::{match_def_path, paths};
|
use clippy_utils::{match_def_path, paths};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::{Body, CoroutineKind, CoroutineDesugaring};
|
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::mir::CoroutineLayout;
|
use rustc_middle::mir::CoroutineLayout;
|
||||||
use rustc_session::impl_lint_pass;
|
use rustc_session::impl_lint_pass;
|
||||||
@ -183,8 +183,8 @@ impl AwaitHolding {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LateLintPass<'_> for AwaitHolding {
|
impl<'tcx> LateLintPass<'tcx> for AwaitHolding {
|
||||||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
|
||||||
for conf in &self.conf_invalid_types {
|
for conf in &self.conf_invalid_types {
|
||||||
let segs: Vec<_> = conf.path().split("::").collect();
|
let segs: Vec<_> = conf.path().split("::").collect();
|
||||||
for id in clippy_utils::def_path_def_ids(cx, &segs) {
|
for id in clippy_utils::def_path_def_ids(cx, &segs) {
|
||||||
@ -193,10 +193,14 @@ impl LateLintPass<'_> for AwaitHolding {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||||
if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) = body.coroutine_kind {
|
if let hir::ExprKind::Closure(hir::Closure {
|
||||||
let def_id = cx.tcx.hir().body_owner_def_id(body.id());
|
kind: hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)),
|
||||||
if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(def_id) {
|
def_id,
|
||||||
|
..
|
||||||
|
}) = expr.kind
|
||||||
|
{
|
||||||
|
if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(*def_id) {
|
||||||
self.check_interior_types(cx, coroutine_layout);
|
self.check_interior_types(cx, coroutine_layout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,9 @@ use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt};
|
|||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::intravisit::FnKind;
|
use rustc_hir::intravisit::FnKind;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
Block, Body, Closure, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound,
|
Block, Body, Closure, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, FnRetTy,
|
||||||
ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind,
|
GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind,
|
||||||
|
TypeBindingKind, ClosureKind,
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
@ -171,16 +172,25 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName])
|
|||||||
.all(|in_lt| output_lifetimes.iter().any(|out_lt| in_lt == out_lt))
|
.all(|in_lt| output_lifetimes.iter().any(|out_lt| in_lt == out_lt))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
|
fn desugared_async_block<'tcx>(
|
||||||
if let Some(block_expr) = block.expr
|
cx: &LateContext<'tcx>,
|
||||||
&& let Expr {
|
block: &'tcx Block<'tcx>,
|
||||||
kind: ExprKind::Closure(&Closure { body, .. }),
|
) -> Option<&'tcx Body<'tcx>> {
|
||||||
|
if let Some(Expr {
|
||||||
|
kind:
|
||||||
|
ExprKind::Closure(&Closure {
|
||||||
|
kind:
|
||||||
|
ClosureKind::Coroutine(CoroutineKind::Desugared(
|
||||||
|
CoroutineDesugaring::Async,
|
||||||
|
CoroutineSource::Block,
|
||||||
|
)),
|
||||||
|
body,
|
||||||
..
|
..
|
||||||
} = block_expr
|
}),
|
||||||
&& let closure_body = cx.tcx.hir().body(body)
|
..
|
||||||
&& closure_body.coroutine_kind == Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block))
|
}) = block.expr
|
||||||
{
|
{
|
||||||
return Some(closure_body);
|
return Some(cx.tcx.hir().body(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
|
@ -32,7 +32,6 @@ pub(super) fn check<'tcx>(
|
|||||||
&& let Body {
|
&& let Body {
|
||||||
params: [p],
|
params: [p],
|
||||||
value: body_expr,
|
value: body_expr,
|
||||||
coroutine_kind: _,
|
|
||||||
} = cx.tcx.hir().body(c.body)
|
} = cx.tcx.hir().body(c.body)
|
||||||
&& let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind
|
&& let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind
|
||||||
&& let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) {
|
&& let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) {
|
||||||
|
@ -3,7 +3,7 @@ use clippy_utils::path_res;
|
|||||||
use clippy_utils::source::snippet;
|
use clippy_utils::source::snippet;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::{Block, Body, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, LangItem, MatchSource, QPath};
|
use rustc_hir::{Block, Body, Expr, ExprKind, LangItem, MatchSource, QPath};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
|
|
||||||
@ -86,7 +86,6 @@ impl LateLintPass<'_> for NeedlessQuestionMark {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
|
fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
|
||||||
if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Fn)) = body.coroutine_kind {
|
|
||||||
if let ExprKind::Block(
|
if let ExprKind::Block(
|
||||||
Block {
|
Block {
|
||||||
expr:
|
expr:
|
||||||
@ -100,8 +99,7 @@ impl LateLintPass<'_> for NeedlessQuestionMark {
|
|||||||
) = body.value.kind
|
) = body.value.kind
|
||||||
{
|
{
|
||||||
if let ExprKind::Block(Block { expr: Some(expr), .. }, ..) = async_body.kind {
|
if let ExprKind::Block(Block { expr: Some(expr), .. }, ..) = async_body.kind {
|
||||||
check(cx, expr);
|
check(cx, expr.peel_blocks());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
check(cx, body.value.peel_blocks());
|
check(cx, body.value.peel_blocks());
|
||||||
|
@ -5,7 +5,7 @@ use clippy_utils::peel_blocks;
|
|||||||
use clippy_utils::source::{snippet, walk_span_to_context};
|
use clippy_utils::source::{snippet, walk_span_to_context};
|
||||||
use clippy_utils::visitors::for_each_expr;
|
use clippy_utils::visitors::for_each_expr;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Closure, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, MatchSource};
|
use rustc_hir::{Closure, ClosureKind, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, MatchSource};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_middle::ty::UpvarCapture;
|
use rustc_middle::ty::UpvarCapture;
|
||||||
@ -69,9 +69,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock {
|
|||||||
/// If `expr` is a desugared `async` block, return the original expression if it does not capture
|
/// If `expr` is a desugared `async` block, return the original expression if it does not capture
|
||||||
/// any variable by ref.
|
/// any variable by ref.
|
||||||
fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
|
fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
|
||||||
if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind
|
if let ExprKind::Closure(Closure { body, def_id, kind, .. }) = expr.kind
|
||||||
&& let body = cx.tcx.hir().body(*body)
|
&& let body = cx.tcx.hir().body(*body)
|
||||||
&& matches!(body.coroutine_kind, Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)))
|
&& matches!(kind, ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)))
|
||||||
{
|
{
|
||||||
cx.typeck_results()
|
cx.typeck_results()
|
||||||
.closure_min_captures
|
.closure_min_captures
|
||||||
|
@ -5,7 +5,7 @@ use clippy_utils::sugg::Sugg;
|
|||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor};
|
use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor};
|
||||||
use rustc_hir::{intravisit as hir_visit, CoroutineKind, CoroutineSource, CoroutineDesugaring, Node};
|
use rustc_hir::{intravisit as hir_visit, CoroutineKind, CoroutineSource, CoroutineDesugaring, Node, ClosureKind};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
@ -63,11 +63,10 @@ impl<'tcx> Visitor<'tcx> for ReturnVisitor {
|
|||||||
/// Checks if the body is owned by an async closure.
|
/// Checks if the body is owned by an async closure.
|
||||||
/// Returns true for `async || whatever_expression`, but false for `|| async { whatever_expression
|
/// Returns true for `async || whatever_expression`, but false for `|| async { whatever_expression
|
||||||
/// }`.
|
/// }`.
|
||||||
fn is_async_closure(cx: &LateContext<'_>, body: &hir::Body<'_>) -> bool {
|
fn is_async_closure(body: &hir::Body<'_>) -> bool {
|
||||||
if let hir::ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind
|
if let hir::ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind
|
||||||
&& let desugared_inner_closure_body = cx.tcx.hir().body(innermost_closure_generated_by_desugar.body)
|
|
||||||
// checks whether it is `async || whatever_expression`
|
// checks whether it is `async || whatever_expression`
|
||||||
&& let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)) = desugared_inner_closure_body.coroutine_kind
|
&& let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)) = innermost_closure_generated_by_desugar.kind
|
||||||
{
|
{
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
@ -103,7 +102,7 @@ fn find_innermost_closure<'tcx>(
|
|||||||
data = Some((
|
data = Some((
|
||||||
body.value,
|
body.value,
|
||||||
closure.fn_decl,
|
closure.fn_decl,
|
||||||
if is_async_closure(cx, body) {
|
if is_async_closure(body) {
|
||||||
ty::Asyncness::Yes
|
ty::Asyncness::Yes
|
||||||
} else {
|
} else {
|
||||||
ty::Asyncness::No
|
ty::Asyncness::No
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||||
use clippy_utils::is_def_id_trait_method;
|
use clippy_utils::is_def_id_trait_method;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::intravisit::{walk_body, walk_expr, walk_fn, FnKind, Visitor};
|
use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor};
|
||||||
use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource};
|
use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
@ -78,32 +78,32 @@ impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> {
|
|||||||
self.await_in_async_block = Some(ex.span);
|
self.await_in_async_block = Some(ex.span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
walk_expr(self, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn nested_visit_map(&mut self) -> Self::Map {
|
|
||||||
self.cx.tcx.hir()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_body(&mut self, b: &'tcx Body<'tcx>) {
|
|
||||||
let is_async_block = matches!(
|
let is_async_block = matches!(
|
||||||
b.coroutine_kind,
|
ex.kind,
|
||||||
Some(rustc_hir::CoroutineKind::Desugared(
|
ExprKind::Closure(rustc_hir::Closure {
|
||||||
|
kind: rustc_hir::ClosureKind::Coroutine(rustc_hir::CoroutineKind::Desugared(
|
||||||
rustc_hir::CoroutineDesugaring::Async,
|
rustc_hir::CoroutineDesugaring::Async,
|
||||||
_
|
_
|
||||||
))
|
)),
|
||||||
|
..
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
if is_async_block {
|
if is_async_block {
|
||||||
self.async_depth += 1;
|
self.async_depth += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
walk_body(self, b);
|
walk_expr(self, ex);
|
||||||
|
|
||||||
if is_async_block {
|
if is_async_block {
|
||||||
self.async_depth -= 1;
|
self.async_depth -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn nested_visit_map(&mut self) -> Self::Map {
|
||||||
|
self.cx.tcx.hir()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
|
impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
|
||||||
|
@ -7,7 +7,8 @@ use rustc_ast::LitIntType;
|
|||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
ArrayLen, BindingAnnotation, CaptureBy, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind,
|
ArrayLen, BindingAnnotation, CaptureBy, Closure, ClosureKind, CoroutineKind, ExprKind, FnRetTy, HirId, Lit,
|
||||||
|
PatKind, QPath, StmtKind, TyKind,
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
@ -476,7 +477,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||||||
capture_clause,
|
capture_clause,
|
||||||
fn_decl,
|
fn_decl,
|
||||||
body: body_id,
|
body: body_id,
|
||||||
movability,
|
kind,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
let capture_clause = match capture_clause {
|
let capture_clause = match capture_clause {
|
||||||
@ -484,7 +485,17 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||||||
CaptureBy::Ref => "Ref",
|
CaptureBy::Ref => "Ref",
|
||||||
};
|
};
|
||||||
|
|
||||||
let movability = OptionPat::new(movability.map(|m| format!("Movability::{m:?}")));
|
let closure_kind = match kind {
|
||||||
|
ClosureKind::Closure => "ClosureKind::Closure".to_string(),
|
||||||
|
ClosureKind::Coroutine(coroutine_kind) => match coroutine_kind {
|
||||||
|
CoroutineKind::Desugared(desugaring, source) => format!(
|
||||||
|
"ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::{desugaring:?}, CoroutineSource::{source:?}))"
|
||||||
|
),
|
||||||
|
CoroutineKind::Coroutine(movability) => {
|
||||||
|
format!("ClosureKind::Coroutine(CoroutineKind::Coroutine(Movability::{movability:?})")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let ret_ty = match fn_decl.output {
|
let ret_ty = match fn_decl.output {
|
||||||
FnRetTy::DefaultReturn(_) => "FnRetTy::DefaultReturn(_)",
|
FnRetTy::DefaultReturn(_) => "FnRetTy::DefaultReturn(_)",
|
||||||
@ -492,7 +503,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
bind!(self, fn_decl, body_id);
|
bind!(self, fn_decl, body_id);
|
||||||
kind!("Closure(CaptureBy::{capture_clause}, {fn_decl}, {body_id}, _, {movability})");
|
kind!(
|
||||||
|
"Closure {{ capture_clause: CaptureBy::{capture_clause}, fn_decl: {fn_decl}, body: {body_id}, closure_kind: {closure_kind}, .. }}"
|
||||||
|
);
|
||||||
chain!(self, "let {ret_ty} = {fn_decl}.output");
|
chain!(self, "let {ret_ty} = {fn_decl}.output");
|
||||||
self.body(body_id);
|
self.body(body_id);
|
||||||
},
|
},
|
||||||
|
@ -40,10 +40,10 @@ if let ExprKind::Block(block, None) = expr.kind
|
|||||||
{
|
{
|
||||||
// report your lint here
|
// report your lint here
|
||||||
}
|
}
|
||||||
if let ExprKind::Closure(CaptureBy::Value { .. }, fn_decl, body_id, _, None) = expr.kind
|
if let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::Closure, .. } = expr.kind
|
||||||
&& let FnRetTy::DefaultReturn(_) = fn_decl.output
|
&& let FnRetTy::DefaultReturn(_) = fn_decl.output
|
||||||
&& expr1 = &cx.tcx.hir().body(body_id).value
|
&& expr1 = &cx.tcx.hir().body(body_id).value
|
||||||
&& let ExprKind::Closure(CaptureBy::Value { .. }, fn_decl1, body_id1, _, Some(Movability::Static)) = expr1.kind
|
&& let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl1, body: body_id1, closure_kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)), .. } = expr1.kind
|
||||||
&& let FnRetTy::DefaultReturn(_) = fn_decl1.output
|
&& let FnRetTy::DefaultReturn(_) = fn_decl1.output
|
||||||
&& expr2 = &cx.tcx.hir().body(body_id1).value
|
&& expr2 = &cx.tcx.hir().body(body_id1).value
|
||||||
&& let ExprKind::Block(block, None) = expr2.kind
|
&& let ExprKind::Block(block, None) = expr2.kind
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
if let StmtKind::Local(local) = stmt.kind
|
if let StmtKind::Local(local) = stmt.kind
|
||||||
&& let Some(init) = local.init
|
&& let Some(init) = local.init
|
||||||
&& let ExprKind::Closure(CaptureBy::Ref, fn_decl, body_id, _, None) = init.kind
|
&& let ExprKind::Closure { capture_clause: CaptureBy::Ref, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::Closure, .. } = init.kind
|
||||||
&& let FnRetTy::DefaultReturn(_) = fn_decl.output
|
&& let FnRetTy::DefaultReturn(_) = fn_decl.output
|
||||||
&& expr = &cx.tcx.hir().body(body_id).value
|
&& expr = &cx.tcx.hir().body(body_id).value
|
||||||
&& let ExprKind::Block(block, None) = expr.kind
|
&& let ExprKind::Block(block, None) = expr.kind
|
||||||
|
@ -135,3 +135,7 @@ async fn async_deref_ref(s: Option<&String>) -> Option<&str> {
|
|||||||
async fn async_result_bad(s: TR) -> Result<usize, bool> {
|
async fn async_result_bad(s: TR) -> Result<usize, bool> {
|
||||||
s.magic
|
s.magic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn async_wrapped<T>(a: Option<T>) -> Option<T> {
|
||||||
|
{ a }
|
||||||
|
}
|
||||||
|
@ -135,3 +135,7 @@ async fn async_deref_ref(s: Option<&String>) -> Option<&str> {
|
|||||||
async fn async_result_bad(s: TR) -> Result<usize, bool> {
|
async fn async_result_bad(s: TR) -> Result<usize, bool> {
|
||||||
Ok(s.magic?)
|
Ok(s.magic?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn async_wrapped<T>(a: Option<T>) -> Option<T> {
|
||||||
|
{ Some(a?) }
|
||||||
|
}
|
||||||
|
@ -90,5 +90,11 @@ error: question mark operator is useless here
|
|||||||
LL | Ok(s.magic?)
|
LL | Ok(s.magic?)
|
||||||
| ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `s.magic`
|
| ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `s.magic`
|
||||||
|
|
||||||
error: aborting due to 14 previous errors
|
error: question mark operator is useless here
|
||||||
|
--> $DIR/needless_question_mark.rs:140:7
|
||||||
|
|
|
||||||
|
LL | { Some(a?) }
|
||||||
|
| ^^^^^^^^ help: try removing question mark and `Some()`: `a`
|
||||||
|
|
||||||
|
error: aborting due to 15 previous errors
|
||||||
|
|
||||||
|
@ -125,9 +125,9 @@ hir-stats ExprField 40 ( 0.4%) 1 40
|
|||||||
hir-stats TraitItemRef 56 ( 0.6%) 2 28
|
hir-stats TraitItemRef 56 ( 0.6%) 2 28
|
||||||
hir-stats Local 64 ( 0.7%) 1 64
|
hir-stats Local 64 ( 0.7%) 1 64
|
||||||
hir-stats Param 64 ( 0.7%) 2 32
|
hir-stats Param 64 ( 0.7%) 2 32
|
||||||
|
hir-stats Body 72 ( 0.8%) 3 24
|
||||||
hir-stats InlineAsm 72 ( 0.8%) 1 72
|
hir-stats InlineAsm 72 ( 0.8%) 1 72
|
||||||
hir-stats ImplItemRef 72 ( 0.8%) 2 36
|
hir-stats ImplItemRef 72 ( 0.8%) 2 36
|
||||||
hir-stats Body 96 ( 1.1%) 3 32
|
|
||||||
hir-stats FieldDef 96 ( 1.1%) 2 48
|
hir-stats FieldDef 96 ( 1.1%) 2 48
|
||||||
hir-stats Arm 96 ( 1.1%) 2 48
|
hir-stats Arm 96 ( 1.1%) 2 48
|
||||||
hir-stats Stmt 96 ( 1.1%) 3 32
|
hir-stats Stmt 96 ( 1.1%) 3 32
|
||||||
@ -146,7 +146,7 @@ hir-stats - Trait 192 ( 2.1%) 4
|
|||||||
hir-stats WherePredicate 192 ( 2.1%) 3 64
|
hir-stats WherePredicate 192 ( 2.1%) 3 64
|
||||||
hir-stats - BoundPredicate 192 ( 2.1%) 3
|
hir-stats - BoundPredicate 192 ( 2.1%) 3
|
||||||
hir-stats Block 288 ( 3.2%) 6 48
|
hir-stats Block 288 ( 3.2%) 6 48
|
||||||
hir-stats Pat 360 ( 3.9%) 5 72
|
hir-stats Pat 360 ( 4.0%) 5 72
|
||||||
hir-stats - Wild 72 ( 0.8%) 1
|
hir-stats - Wild 72 ( 0.8%) 1
|
||||||
hir-stats - Struct 72 ( 0.8%) 1
|
hir-stats - Struct 72 ( 0.8%) 1
|
||||||
hir-stats - Binding 216 ( 2.4%) 3
|
hir-stats - Binding 216 ( 2.4%) 3
|
||||||
@ -172,7 +172,7 @@ hir-stats - Impl 88 ( 1.0%) 1
|
|||||||
hir-stats - Fn 176 ( 1.9%) 2
|
hir-stats - Fn 176 ( 1.9%) 2
|
||||||
hir-stats - Use 352 ( 3.9%) 4
|
hir-stats - Use 352 ( 3.9%) 4
|
||||||
hir-stats Path 1_240 (13.6%) 31 40
|
hir-stats Path 1_240 (13.6%) 31 40
|
||||||
hir-stats PathSegment 1_920 (21.0%) 40 48
|
hir-stats PathSegment 1_920 (21.1%) 40 48
|
||||||
hir-stats ----------------------------------------------------------------
|
hir-stats ----------------------------------------------------------------
|
||||||
hir-stats Total 9_136
|
hir-stats Total 9_112
|
||||||
hir-stats
|
hir-stats
|
||||||
|
Loading…
Reference in New Issue
Block a user