mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Better account for FnOnce
in move errors
``` error[E0382]: use of moved value: `blk` --> $DIR/once-cant-call-twice-on-heap.rs:8:5 | LL | fn foo<F:FnOnce()>(blk: F) { | --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait LL | blk(); | ----- `blk` moved due to this call LL | blk(); | ^^^ value used here after move | note: `FnOnce` closures can only be called once --> $DIR/once-cant-call-twice-on-heap.rs:6:10 | LL | fn foo<F:FnOnce()>(blk: F) { | ^^^^^^^^ `F` is made to be an `FnOnce` closure here LL | blk(); | ----- this value implements `FnOnce`, which causes it to be moved when called ```
This commit is contained in:
parent
dfe28debb9
commit
4ca876b7a4
@ -87,6 +87,12 @@ borrowck_move_unsized =
|
|||||||
borrowck_moved_a_fn_once_in_call =
|
borrowck_moved_a_fn_once_in_call =
|
||||||
this value implements `FnOnce`, which causes it to be moved when called
|
this value implements `FnOnce`, which causes it to be moved when called
|
||||||
|
|
||||||
|
borrowck_moved_a_fn_once_in_call_call =
|
||||||
|
`FnOnce` closures can only be called once
|
||||||
|
|
||||||
|
borrowck_moved_a_fn_once_in_call_def =
|
||||||
|
`{$ty}` is made to be an `FnOnce` closure here
|
||||||
|
|
||||||
borrowck_moved_due_to_await =
|
borrowck_moved_due_to_await =
|
||||||
{$place_name} {$is_partial ->
|
{$place_name} {$is_partial ->
|
||||||
[true] partially moved
|
[true] partially moved
|
||||||
|
@ -283,7 +283,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
Some(name) => format!("`{name}`"),
|
Some(name) => format!("`{name}`"),
|
||||||
None => "value".to_owned(),
|
None => "value".to_owned(),
|
||||||
};
|
};
|
||||||
if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, ¬e_msg) {
|
if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, ¬e_msg)
|
||||||
|
|| if let UseSpans::FnSelfUse { kind, .. } = use_spans
|
||||||
|
&& let CallKind::FnCall { fn_trait_id, self_ty } = kind
|
||||||
|
&& let ty::Param(_) = self_ty.kind()
|
||||||
|
&& ty == self_ty
|
||||||
|
&& Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait()
|
||||||
|
{
|
||||||
|
// this is a type parameter `T: FnOnce()`, don't suggest `T: FnOnce() + Clone`.
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
{
|
||||||
// Suppress the next suggestion since we don't want to put more bounds onto
|
// Suppress the next suggestion since we don't want to put more bounds onto
|
||||||
// something that already has `Fn`-like bounds (or is a closure), so we can't
|
// something that already has `Fn`-like bounds (or is a closure), so we can't
|
||||||
// restrict anyways.
|
// restrict anyways.
|
||||||
@ -1016,7 +1028,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
&& { true }
|
|
||||||
&& parent_binop == other_parent_binop
|
&& parent_binop == other_parent_binop
|
||||||
{
|
{
|
||||||
// Explicitly look for `expr += other_expr;` and avoid suggesting
|
// Explicitly look for `expr += other_expr;` and avoid suggesting
|
||||||
|
@ -5,6 +5,7 @@ use crate::session_diagnostics::{
|
|||||||
CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
|
CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
|
||||||
};
|
};
|
||||||
use rustc_errors::{Applicability, Diag};
|
use rustc_errors::{Applicability, Diag};
|
||||||
|
use rustc_errors::{DiagCtxt, MultiSpan};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorKind, Namespace};
|
use rustc_hir::def::{CtorKind, Namespace};
|
||||||
use rustc_hir::CoroutineKind;
|
use rustc_hir::CoroutineKind;
|
||||||
@ -29,6 +30,8 @@ use rustc_trait_selection::infer::InferCtxtExt;
|
|||||||
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
|
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
|
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
|
||||||
|
|
||||||
|
use crate::fluent_generated as fluent;
|
||||||
|
|
||||||
use super::borrow_set::BorrowData;
|
use super::borrow_set::BorrowData;
|
||||||
use super::MirBorrowckCtxt;
|
use super::MirBorrowckCtxt;
|
||||||
|
|
||||||
@ -587,7 +590,7 @@ impl UseSpans<'_> {
|
|||||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub(super) fn args_subdiag(
|
pub(super) fn args_subdiag(
|
||||||
self,
|
self,
|
||||||
dcx: &rustc_errors::DiagCtxt,
|
dcx: &DiagCtxt,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
f: impl FnOnce(Span) -> CaptureArgLabel,
|
f: impl FnOnce(Span) -> CaptureArgLabel,
|
||||||
) {
|
) {
|
||||||
@ -601,7 +604,7 @@ impl UseSpans<'_> {
|
|||||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub(super) fn var_path_only_subdiag(
|
pub(super) fn var_path_only_subdiag(
|
||||||
self,
|
self,
|
||||||
dcx: &rustc_errors::DiagCtxt,
|
dcx: &DiagCtxt,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
action: crate::InitializationRequiringAction,
|
action: crate::InitializationRequiringAction,
|
||||||
) {
|
) {
|
||||||
@ -639,7 +642,7 @@ impl UseSpans<'_> {
|
|||||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub(super) fn var_subdiag(
|
pub(super) fn var_subdiag(
|
||||||
self,
|
self,
|
||||||
dcx: &rustc_errors::DiagCtxt,
|
dcx: &DiagCtxt,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
kind: Option<rustc_middle::mir::BorrowKind>,
|
kind: Option<rustc_middle::mir::BorrowKind>,
|
||||||
f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause,
|
f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause,
|
||||||
@ -1034,7 +1037,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
.map(|n| format!("`{n}`"))
|
.map(|n| format!("`{n}`"))
|
||||||
.unwrap_or_else(|| "value".to_owned());
|
.unwrap_or_else(|| "value".to_owned());
|
||||||
match kind {
|
match kind {
|
||||||
CallKind::FnCall { fn_trait_id, .. }
|
CallKind::FnCall { fn_trait_id, self_ty }
|
||||||
if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
|
if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
|
||||||
{
|
{
|
||||||
err.subdiagnostic(
|
err.subdiagnostic(
|
||||||
@ -1046,7 +1049,58 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
is_loop_message,
|
is_loop_message,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
err.subdiagnostic(self.dcx(), CaptureReasonNote::FnOnceMoveInCall { var_span });
|
if let ty::Param(param_ty) = self_ty.kind()
|
||||||
|
&& let generics = self.infcx.tcx.generics_of(self.mir_def_id())
|
||||||
|
&& let param = generics.type_param(param_ty, self.infcx.tcx)
|
||||||
|
&& let Some(hir_generics) = self
|
||||||
|
.infcx
|
||||||
|
.tcx
|
||||||
|
.typeck_root_def_id(self.mir_def_id().to_def_id())
|
||||||
|
.as_local()
|
||||||
|
.and_then(|def_id| self.infcx.tcx.hir().get_generics(def_id))
|
||||||
|
&& let spans = hir_generics
|
||||||
|
.predicates
|
||||||
|
.iter()
|
||||||
|
.filter_map(|pred| match pred {
|
||||||
|
hir::WherePredicate::BoundPredicate(pred) => Some(pred),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.filter(|pred| {
|
||||||
|
if let Some((id, _)) = pred.bounded_ty.as_generic_param() {
|
||||||
|
id == param.def_id
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.flat_map(|pred| pred.bounds)
|
||||||
|
.filter_map(|bound| {
|
||||||
|
if let Some(trait_ref) = bound.trait_ref()
|
||||||
|
&& let Some(trait_def_id) = trait_ref.trait_def_id()
|
||||||
|
&& trait_def_id == fn_trait_id
|
||||||
|
{
|
||||||
|
Some(bound.span())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<Span>>()
|
||||||
|
&& !spans.is_empty()
|
||||||
|
{
|
||||||
|
let mut span: MultiSpan = spans.clone().into();
|
||||||
|
for sp in spans {
|
||||||
|
span.push_span_label(sp, fluent::borrowck_moved_a_fn_once_in_call_def);
|
||||||
|
}
|
||||||
|
span.push_span_label(
|
||||||
|
fn_call_span,
|
||||||
|
fluent::borrowck_moved_a_fn_once_in_call,
|
||||||
|
);
|
||||||
|
err.span_note(span, fluent::borrowck_moved_a_fn_once_in_call_call);
|
||||||
|
} else {
|
||||||
|
err.subdiagnostic(
|
||||||
|
self.dcx(),
|
||||||
|
CaptureReasonNote::FnOnceMoveInCall { var_span },
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CallKind::Operator { self_arg, trait_id, .. } => {
|
CallKind::Operator { self_arg, trait_id, .. } => {
|
||||||
let self_arg = self_arg.unwrap();
|
let self_arg = self_arg.unwrap();
|
||||||
|
@ -29,15 +29,13 @@ LL | f(1, 2);
|
|||||||
LL | f(1, 2);
|
LL | f(1, 2);
|
||||||
| ^ value used here after move
|
| ^ value used here after move
|
||||||
|
|
|
|
||||||
note: this value implements `FnOnce`, which causes it to be moved when called
|
note: `FnOnce` closures can only be called once
|
||||||
--> $DIR/borrowck-unboxed-closures.rs:11:5
|
--> $DIR/borrowck-unboxed-closures.rs:10:8
|
||||||
|
|
|
|
||||||
|
LL | fn c<F:FnOnce(isize, isize) -> isize>(f: F) {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `F` is made to be an `FnOnce` closure here
|
||||||
LL | f(1, 2);
|
LL | f(1, 2);
|
||||||
| ^
|
| ------- this value implements `FnOnce`, which causes it to be moved when called
|
||||||
help: consider further restricting this bound
|
|
||||||
|
|
|
||||||
LL | fn c<F:FnOnce(isize, isize) -> isize + Copy>(f: F) {
|
|
||||||
| ++++++
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
@ -8,15 +8,13 @@ LL | blk();
|
|||||||
LL | blk();
|
LL | blk();
|
||||||
| ^^^ value used here after move
|
| ^^^ value used here after move
|
||||||
|
|
|
|
||||||
note: this value implements `FnOnce`, which causes it to be moved when called
|
note: `FnOnce` closures can only be called once
|
||||||
--> $DIR/once-cant-call-twice-on-heap.rs:7:5
|
--> $DIR/once-cant-call-twice-on-heap.rs:6:10
|
||||||
|
|
|
|
||||||
|
LL | fn foo<F:FnOnce()>(blk: F) {
|
||||||
|
| ^^^^^^^^ `F` is made to be an `FnOnce` closure here
|
||||||
LL | blk();
|
LL | blk();
|
||||||
| ^^^
|
| ----- this value implements `FnOnce`, which causes it to be moved when called
|
||||||
help: consider further restricting this bound
|
|
||||||
|
|
|
||||||
LL | fn foo<F:FnOnce() + Copy>(blk: F) {
|
|
||||||
| ++++++
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user