Skip to content

Commit 0faba1b

Browse files
authored
Rollup merge of rust-lang#94375 - WaffleLapkin:copy-suggestion, r=estebank
Adt copy suggestions Previously we've only suggested adding `Copy` bounds when the type being moved/copied is a type parameter (generic). With this PR we also suggest adding bounds when a type - Can be copy - All predicates that need to be satisfied for that are based on type params i.e. we will suggest `T: Copy` for `Option<T>`, but won't suggest anything for `Option<String>`. An example: ```rust fn duplicate<T>(t: Option<T>) -> (Option<T>, Option<T>) { (t, t) } ``` New error (current compiler doesn't provide `help`:): ```text error[E0382]: use of moved value: `t` --> t.rs:2:9 | 1 | fn duplicate<T>(t: Option<T>) -> (Option<T>, Option<T>) { | - move occurs because `t` has type `Option<T>`, which does not implement the `Copy` trait 2 | (t, t) | - ^ value used here after move | | | value moved here | help: consider restricting type parameter `T` | 1 | fn duplicate<T: Copy>(t: Option<T>) -> (Option<T>, Option<T>) { | ++++++ ``` Fixes rust-lang#93623 r? ```@estebank``` ```@rustbot``` label +A-diagnostics +A-suggestion-diagnostics +C-enhancement ---- I'm not at all sure if this is the right implementation for this kind of suggestion, but it seems to work :')
2 parents cbc64a1 + f0a16b8 commit 0faba1b

8 files changed

+608
-164
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+62-1
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,21 @@ use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported};
55
use rustc_hir as hir;
66
use rustc_hir::def_id::DefId;
77
use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
8+
use rustc_infer::infer::TyCtxtInferExt;
9+
use rustc_infer::traits::ObligationCause;
810
use rustc_middle::mir::{
911
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
1012
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
1113
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
1214
};
13-
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
15+
use rustc_middle::ty::{
16+
self, suggest_constraining_type_param, suggest_constraining_type_params, PredicateKind, Ty,
17+
};
1418
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
1519
use rustc_span::symbol::sym;
1620
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
1721
use rustc_trait_selection::infer::InferCtxtExt;
22+
use rustc_trait_selection::traits::TraitEngineExt as _;
1823

1924
use crate::borrow_set::TwoPhaseActivation;
2025
use crate::borrowck_errors;
@@ -423,7 +428,63 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
423428
None,
424429
);
425430
}
431+
} else {
432+
// Try to find predicates on *generic params* that would allow copying `ty`
433+
434+
let tcx = self.infcx.tcx;
435+
let generics = tcx.generics_of(self.mir_def_id());
436+
if let Some(hir_generics) = tcx
437+
.typeck_root_def_id(self.mir_def_id().to_def_id())
438+
.as_local()
439+
.and_then(|def_id| tcx.hir().get_generics(def_id))
440+
{
441+
let predicates: Result<Vec<_>, _> = tcx.infer_ctxt().enter(|infcx| {
442+
let mut fulfill_cx =
443+
<dyn rustc_infer::traits::TraitEngine<'_>>::new(infcx.tcx);
444+
445+
let copy_did = infcx.tcx.lang_items().copy_trait().unwrap();
446+
let cause = ObligationCause::new(
447+
span,
448+
self.mir_hir_id(),
449+
rustc_infer::traits::ObligationCauseCode::MiscObligation,
450+
);
451+
fulfill_cx.register_bound(&infcx, self.param_env, ty, copy_did, cause);
452+
let errors = fulfill_cx.select_where_possible(&infcx);
453+
454+
// Only emit suggestion if all required predicates are on generic
455+
errors
456+
.into_iter()
457+
.map(|err| match err.obligation.predicate.kind().skip_binder() {
458+
PredicateKind::Trait(predicate) => {
459+
match predicate.self_ty().kind() {
460+
ty::Param(param_ty) => Ok((
461+
generics.type_param(param_ty, tcx),
462+
predicate
463+
.trait_ref
464+
.print_only_trait_path()
465+
.to_string(),
466+
)),
467+
_ => Err(()),
468+
}
469+
}
470+
_ => Err(()),
471+
})
472+
.collect()
473+
});
474+
475+
if let Ok(predicates) = predicates {
476+
suggest_constraining_type_params(
477+
tcx,
478+
hir_generics,
479+
&mut err,
480+
predicates.iter().map(|(param, constraint)| {
481+
(param.name.as_str(), &**constraint, None)
482+
}),
483+
);
484+
}
485+
}
426486
}
487+
427488
let span = if let Some(local) = place.as_local() {
428489
let decl = &self.body.local_decls[local];
429490
Some(decl.source_info.span)

compiler/rustc_middle/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#![feature(nonzero_ops)]
5757
#![feature(unwrap_infallible)]
5858
#![feature(decl_macro)]
59+
#![feature(drain_filter)]
5960
#![recursion_limit = "512"]
6061
#![allow(rustc::potential_query_instability)]
6162

0 commit comments

Comments
 (0)