Skip to content

Commit 210a672

Browse files
committed
Deduplicate some logic
1 parent a754fca commit 210a672

File tree

3 files changed

+161
-181
lines changed

3 files changed

+161
-181
lines changed

compiler/rustc_borrowck/src/diagnostics/mod.rs

+51-110
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_hir::def::{CtorKind, Namespace};
1111
use rustc_hir::CoroutineKind;
1212
use rustc_index::IndexSlice;
1313
use rustc_infer::infer::BoundRegionConversionTime;
14-
use rustc_infer::traits::{FulfillmentErrorCode, SelectionError, TraitEngine, TraitEngineExt};
14+
use rustc_infer::traits::{FulfillmentErrorCode, SelectionError};
1515
use rustc_middle::mir::tcx::PlaceTy;
1616
use rustc_middle::mir::{
1717
AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location,
@@ -25,11 +25,9 @@ use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
2525
use rustc_span::def_id::LocalDefId;
2626
use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
2727
use rustc_target::abi::{FieldIdx, VariantIdx};
28-
use rustc_trait_selection::solve::FulfillmentCtxt;
28+
use rustc_trait_selection::infer::InferCtxtExt;
2929
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
30-
use rustc_trait_selection::traits::{
31-
type_known_to_meet_bound_modulo_regions, Obligation, ObligationCause,
32-
};
30+
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
3331

3432
use super::borrow_set::BorrowData;
3533
use super::MirBorrowckCtxt;
@@ -1175,113 +1173,56 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
11751173
} else {
11761174
vec![(move_span.shrink_to_hi(), ".clone()".to_string())]
11771175
};
1178-
self.infcx.probe(|_snapshot| {
1179-
if let ty::Adt(def, args) = ty.kind()
1180-
&& !has_sugg
1181-
&& let Some((def_id, _imp)) = tcx
1182-
.all_impls(clone_trait)
1183-
.filter_map(|def_id| {
1184-
tcx.impl_trait_ref(def_id).map(|r| (def_id, r))
1185-
})
1186-
.map(|(def_id, imp)| (def_id, imp.skip_binder()))
1187-
.filter(|(_, imp)| match imp.self_ty().peel_refs().kind() {
1188-
ty::Adt(i_def, _) if i_def.did() == def.did() => true,
1189-
_ => false,
1190-
})
1191-
.next()
1192-
{
1193-
let mut fulfill_cx = FulfillmentCtxt::new(self.infcx);
1194-
// We get all obligations from the impl to talk about specific
1195-
// trait bounds.
1196-
let obligations = tcx
1197-
.predicates_of(def_id)
1198-
.instantiate(tcx, args)
1199-
.into_iter()
1200-
.map(|(clause, span)| {
1201-
Obligation::new(
1202-
tcx,
1203-
ObligationCause::misc(
1204-
span,
1205-
self.body.source.def_id().expect_local(),
1206-
),
1207-
self.param_env,
1208-
clause,
1209-
)
1210-
})
1211-
.collect::<Vec<_>>();
1212-
fulfill_cx
1213-
.register_predicate_obligations(self.infcx, obligations);
1214-
// We also register the parent obligation for the type at hand
1215-
// implementing `Clone`, to account for bounds that also need
1216-
// to be evaluated, like ensuring that `Self: Clone`.
1217-
let trait_ref = ty::TraitRef::new(tcx, clone_trait, [ty]);
1218-
let obligation = Obligation::new(
1219-
tcx,
1220-
ObligationCause::dummy(),
1221-
self.param_env,
1222-
trait_ref,
1223-
);
1224-
fulfill_cx
1225-
.register_predicate_obligation(self.infcx, obligation);
1226-
let errors = fulfill_cx.select_all_or_error(self.infcx);
1227-
// We remove the last predicate failure, which corresponds to
1228-
// the top-level obligation, because most of the type we only
1229-
// care about the other ones, *except* when it is the only one.
1230-
// This seems to only be relevant for arbitrary self-types.
1231-
// Look at `tests/ui/moves/move-fn-self-receiver.rs`.
1232-
let errors = match &errors[..] {
1233-
errors @ [] | errors @ [_] | [errors @ .., _] => errors,
1234-
};
1235-
let msg = match &errors[..] {
1236-
[] => "you can `clone` the value and consume it, but this \
1237-
might not be your desired behavior"
1238-
.to_string(),
1239-
[error] => {
1240-
format!(
1241-
"you could `clone` the value and consume it, if \
1242-
the `{}` trait bound could be satisfied",
1243-
error.obligation.predicate,
1244-
)
1245-
}
1246-
[errors @ .., last] => {
1247-
format!(
1248-
"you could `clone` the value and consume it, if \
1249-
the following trait bounds could be satisfied: {} \
1250-
and `{}`",
1251-
errors
1252-
.iter()
1253-
.map(|e| format!(
1254-
"`{}`",
1255-
e.obligation.predicate
1256-
))
1257-
.collect::<Vec<_>>()
1258-
.join(", "),
1259-
last.obligation.predicate,
1260-
)
1261-
}
1262-
};
1263-
err.multipart_suggestion_verbose(
1264-
msg,
1265-
sugg.clone(),
1266-
Applicability::MaybeIncorrect,
1267-
);
1268-
for error in errors {
1269-
if let FulfillmentErrorCode::CodeSelectionError(
1270-
SelectionError::Unimplemented,
1271-
) = error.code
1272-
&& let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
1273-
pred,
1274-
)) = error.obligation.predicate.kind().skip_binder()
1275-
{
1276-
self.infcx.err_ctxt().suggest_derive(
1277-
&error.obligation,
1278-
err,
1279-
error.obligation.predicate.kind().rebind(pred),
1280-
);
1281-
}
1176+
if let Some(errors) =
1177+
self.infcx.could_impl_trait(clone_trait, ty, self.param_env)
1178+
&& !has_sugg
1179+
{
1180+
let msg = match &errors[..] {
1181+
[] => "you can `clone` the value and consume it, but this \
1182+
might not be your desired behavior"
1183+
.to_string(),
1184+
[error] => {
1185+
format!(
1186+
"you could `clone` the value and consume it, if \
1187+
the `{}` trait bound could be satisfied",
1188+
error.obligation.predicate,
1189+
)
1190+
}
1191+
[errors @ .., last] => {
1192+
format!(
1193+
"you could `clone` the value and consume it, if \
1194+
the following trait bounds could be satisfied: {} \
1195+
and `{}`",
1196+
errors
1197+
.iter()
1198+
.map(|e| format!("`{}`", e.obligation.predicate))
1199+
.collect::<Vec<_>>()
1200+
.join(", "),
1201+
last.obligation.predicate,
1202+
)
1203+
}
1204+
};
1205+
err.multipart_suggestion_verbose(
1206+
msg,
1207+
sugg.clone(),
1208+
Applicability::MaybeIncorrect,
1209+
);
1210+
for error in errors {
1211+
if let FulfillmentErrorCode::CodeSelectionError(
1212+
SelectionError::Unimplemented,
1213+
) = error.code
1214+
&& let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
1215+
pred,
1216+
)) = error.obligation.predicate.kind().skip_binder()
1217+
{
1218+
self.infcx.err_ctxt().suggest_derive(
1219+
&error.obligation,
1220+
err,
1221+
error.obligation.predicate.kind().rebind(pred),
1222+
);
12821223
}
12831224
}
1284-
});
1225+
}
12851226
}
12861227
}
12871228
}

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+38-71
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use rustc_hir::{
2121
StmtKind, TyKind, WherePredicate,
2222
};
2323
use rustc_hir_analysis::astconv::AstConv;
24-
use rustc_infer::traits::{self, StatementAsExpression, TraitEngineExt};
24+
use rustc_infer::traits::{self, StatementAsExpression};
2525
use rustc_middle::lint::in_external_macro;
2626
use rustc_middle::middle::stability::EvalResult;
2727
use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -34,7 +34,6 @@ use rustc_span::source_map::Spanned;
3434
use rustc_span::symbol::{sym, Ident};
3535
use rustc_span::{Span, Symbol};
3636
use rustc_trait_selection::infer::InferCtxtExt;
37-
use rustc_trait_selection::solve::FulfillmentCtxt;
3837
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
3938
use rustc_trait_selection::traits::error_reporting::DefIdOrName;
4039
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -1620,78 +1619,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16201619
None,
16211620
);
16221621
} else {
1623-
self.infcx.probe(|_snapshot| {
1624-
if let ty::Adt(def, args) = expected_ty.kind()
1625-
&& let Some((def_id, _imp)) = self
1626-
.tcx
1627-
.all_impls(clone_trait_did)
1628-
.filter_map(|def_id| {
1629-
self.tcx.impl_trait_ref(def_id).map(|r| (def_id, r))
1630-
})
1631-
.map(|(def_id, imp)| (def_id, imp.skip_binder()))
1632-
.filter(|(_, imp)| match imp.self_ty().peel_refs().kind() {
1633-
ty::Adt(i_def, _) if i_def.did() == def.did() => true,
1634-
_ => false,
1635-
})
1636-
.next()
1637-
{
1638-
let mut fulfill_cx = FulfillmentCtxt::new(&self.infcx);
1639-
// We get all obligations from the impl to talk about specific
1640-
// trait bounds.
1641-
let obligations = self
1642-
.tcx
1643-
.predicates_of(def_id)
1644-
.instantiate(self.tcx, args)
1645-
.into_iter()
1646-
.map(|(clause, span)| {
1647-
traits::Obligation::new(
1648-
self.tcx,
1649-
traits::ObligationCause::misc(span, self.body_id),
1650-
self.param_env,
1651-
clause,
1652-
)
1653-
})
1654-
.collect::<Vec<_>>();
1655-
fulfill_cx.register_predicate_obligations(&self.infcx, obligations);
1656-
let errors = fulfill_cx.select_all_or_error(&self.infcx);
1657-
match &errors[..] {
1658-
[] => {}
1659-
[error] => {
1660-
diag.help(format!(
1661-
"`Clone` is not implemented because the trait bound `{}` is \
1662-
not satisfied",
1663-
error.obligation.predicate,
1664-
));
1665-
}
1666-
[errors @ .., last] => {
1667-
diag.help(format!(
1668-
"`Clone` is not implemented because the following trait bounds \
1669-
could not be satisfied: {} and `{}`",
1670-
errors
1671-
.iter()
1672-
.map(|e| format!("`{}`", e.obligation.predicate))
1673-
.collect::<Vec<_>>()
1674-
.join(", "),
1675-
last.obligation.predicate,
1676-
));
1677-
}
1622+
if let Some(errors) =
1623+
self.could_impl_trait(clone_trait_did, expected_ty, self.param_env)
1624+
{
1625+
match &errors[..] {
1626+
[] => {}
1627+
[error] => {
1628+
diag.help(format!(
1629+
"`Clone` is not implemented because the trait bound `{}` is \
1630+
not satisfied",
1631+
error.obligation.predicate,
1632+
));
16781633
}
1679-
for error in errors {
1680-
if let traits::FulfillmentErrorCode::CodeSelectionError(
1681-
traits::SelectionError::Unimplemented,
1682-
) = error.code
1683-
&& let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
1684-
error.obligation.predicate.kind().skip_binder()
1685-
{
1686-
self.infcx.err_ctxt().suggest_derive(
1687-
&error.obligation,
1688-
diag,
1689-
error.obligation.predicate.kind().rebind(pred),
1690-
);
1691-
}
1634+
[errors @ .., last] => {
1635+
diag.help(format!(
1636+
"`Clone` is not implemented because the following trait bounds \
1637+
could not be satisfied: {} and `{}`",
1638+
errors
1639+
.iter()
1640+
.map(|e| format!("`{}`", e.obligation.predicate))
1641+
.collect::<Vec<_>>()
1642+
.join(", "),
1643+
last.obligation.predicate,
1644+
));
16921645
}
16931646
}
1694-
});
1647+
for error in errors {
1648+
if let traits::FulfillmentErrorCode::CodeSelectionError(
1649+
traits::SelectionError::Unimplemented,
1650+
) = error.code
1651+
&& let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
1652+
error.obligation.predicate.kind().skip_binder()
1653+
{
1654+
self.infcx.err_ctxt().suggest_derive(
1655+
&error.obligation,
1656+
diag,
1657+
error.obligation.predicate.kind().rebind(pred),
1658+
);
1659+
}
1660+
}
1661+
}
16951662
self.suggest_derive(diag, &[(trait_ref.to_predicate(self.tcx), None, None)]);
16961663
}
16971664
}

0 commit comments

Comments
 (0)