Suggest adding Copy
bound when Adt is moved out
Previously we've only suggested adding `Copy` bounds when the type being moved/copied is a type parameter (generic). With this commit 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>`. Future work: it would be nice to also suggest adding `.clone()` calls
This commit is contained in:
parent
4c7fb9efb7
commit
400d343796
1 changed files with 62 additions and 1 deletions
|
@ -5,16 +5,21 @@ use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported};
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::mir::{
|
||||
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
|
||||
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
|
||||
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
|
||||
};
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
|
||||
use rustc_middle::ty::{
|
||||
self, suggest_constraining_type_param, suggest_constraining_type_params, PredicateKind, Ty,
|
||||
};
|
||||
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::TraitEngineExt as _;
|
||||
|
||||
use crate::borrow_set::TwoPhaseActivation;
|
||||
use crate::borrowck_errors;
|
||||
|
@ -423,7 +428,63 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
None,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Try to find predicates on *generic params* that would allow copying `ty`
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
let generics = tcx.generics_of(self.mir_def_id());
|
||||
if let Some(hir_generics) = tcx
|
||||
.typeck_root_def_id(self.mir_def_id().to_def_id())
|
||||
.as_local()
|
||||
.and_then(|def_id| tcx.hir().get_generics(def_id))
|
||||
{
|
||||
let predicates: Result<Vec<_>, _> = tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut fulfill_cx =
|
||||
<dyn rustc_infer::traits::TraitEngine<'_>>::new(infcx.tcx);
|
||||
|
||||
let copy_did = infcx.tcx.lang_items().copy_trait().unwrap();
|
||||
let cause = ObligationCause::new(
|
||||
span,
|
||||
self.mir_hir_id(),
|
||||
rustc_infer::traits::ObligationCauseCode::MiscObligation,
|
||||
);
|
||||
fulfill_cx.register_bound(&infcx, self.param_env, ty, copy_did, cause);
|
||||
let errors = fulfill_cx.select_where_possible(&infcx);
|
||||
|
||||
// Only emit suggestion if all required predicates are on generic
|
||||
errors
|
||||
.into_iter()
|
||||
.map(|err| match err.obligation.predicate.kind().skip_binder() {
|
||||
PredicateKind::Trait(predicate) => {
|
||||
match predicate.self_ty().kind() {
|
||||
ty::Param(param_ty) => Ok((
|
||||
generics.type_param(param_ty, tcx),
|
||||
predicate
|
||||
.trait_ref
|
||||
.print_only_trait_path()
|
||||
.to_string(),
|
||||
)),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
_ => Err(()),
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
|
||||
if let Ok(predicates) = predicates {
|
||||
suggest_constraining_type_params(
|
||||
tcx,
|
||||
hir_generics,
|
||||
&mut err,
|
||||
predicates.iter().map(|(param, constraint)| {
|
||||
(param.name.as_str(), &**constraint, None)
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let span = if let Some(local) = place.as_local() {
|
||||
let decl = &self.body.local_decls[local];
|
||||
Some(decl.source_info.span)
|
||||
|
|
Loading…
Add table
Reference in a new issue