Skip to content

Commit 210a672

Browse files
committedDec 4, 2023
Deduplicate some logic
·
1.88.01.76.0
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

Lines changed: 51 additions & 110 deletions
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

Lines changed: 38 additions & 71 deletions
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
}

‎compiler/rustc_trait_selection/src/infer.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
use crate::solve::FulfillmentCtxt;
12
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
23
use crate::traits::{self, DefiningAnchor, ObligationCtxt};
34

45
use rustc_hir::def_id::DefId;
56
use rustc_hir::lang_items::LangItem;
7+
use rustc_infer::traits::{TraitEngine, TraitEngineExt};
68
use rustc_middle::arena::ArenaAllocatable;
79
use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse};
810
use rustc_middle::traits::query::NoSolution;
@@ -35,6 +37,13 @@ pub trait InferCtxtExt<'tcx> {
3537
params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
3638
param_env: ty::ParamEnv<'tcx>,
3739
) -> traits::EvaluationResult;
40+
41+
fn could_impl_trait(
42+
&self,
43+
trait_def_id: DefId,
44+
ty: Ty<'tcx>,
45+
param_env: ty::ParamEnv<'tcx>,
46+
) -> Option<Vec<traits::FulfillmentError<'tcx>>>;
3847
}
3948

4049
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
@@ -76,6 +85,69 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
7685
};
7786
self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
7887
}
88+
89+
fn could_impl_trait(
90+
&self,
91+
trait_def_id: DefId,
92+
ty: Ty<'tcx>,
93+
param_env: ty::ParamEnv<'tcx>,
94+
) -> Option<Vec<traits::FulfillmentError<'tcx>>> {
95+
self.probe(|_snapshot| {
96+
if let ty::Adt(def, args) = ty.kind()
97+
&& let Some((impl_def_id, _)) = self
98+
.tcx
99+
.all_impls(trait_def_id)
100+
.filter_map(|impl_def_id| {
101+
self.tcx.impl_trait_ref(impl_def_id).map(|r| (impl_def_id, r))
102+
})
103+
.map(|(impl_def_id, imp)| (impl_def_id, imp.skip_binder()))
104+
.filter(|(_, imp)| match imp.self_ty().peel_refs().kind() {
105+
ty::Adt(i_def, _) if i_def.did() == def.did() => true,
106+
_ => false,
107+
})
108+
.next()
109+
{
110+
let mut fulfill_cx = FulfillmentCtxt::new(self);
111+
// We get all obligations from the impl to talk about specific
112+
// trait bounds.
113+
let obligations = self
114+
.tcx
115+
.predicates_of(impl_def_id)
116+
.instantiate(self.tcx, args)
117+
.into_iter()
118+
.map(|(clause, span)| {
119+
traits::Obligation::new(
120+
self.tcx,
121+
traits::ObligationCause::dummy_with_span(span),
122+
param_env,
123+
clause,
124+
)
125+
})
126+
.collect::<Vec<_>>();
127+
fulfill_cx.register_predicate_obligations(self, obligations);
128+
let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty]);
129+
let obligation = traits::Obligation::new(
130+
self.tcx,
131+
traits::ObligationCause::dummy(),
132+
param_env,
133+
trait_ref,
134+
);
135+
fulfill_cx.register_predicate_obligation(self, obligation);
136+
let mut errors = fulfill_cx.select_all_or_error(self);
137+
// We remove the last predicate failure, which corresponds to
138+
// the top-level obligation, because most of the type we only
139+
// care about the other ones, *except* when it is the only one.
140+
// This seems to only be relevant for arbitrary self-types.
141+
// Look at `tests/ui/moves/move-fn-self-receiver.rs`.
142+
if errors.len() > 1 {
143+
errors.truncate(errors.len() - 1);
144+
}
145+
Some(errors)
146+
} else {
147+
None
148+
}
149+
})
150+
}
79151
}
80152

81153
pub trait InferCtxtBuilderExt<'tcx> {

0 commit comments

Comments
 (0)
Please sign in to comment.