Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 8 pull requests #91061

Closed
wants to merge 29 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
7a47786
Makes docs for references a little less confusing
WaffleLapkin Aug 26, 2021
9a4530b
Update library/std/src/primitive_docs.rs
WaffleLapkin Aug 26, 2021
26aec6c
Update core primitives_docs.rs up to date with std
WaffleLapkin Oct 10, 2021
8f6fa4f
Add a regression test for #87573
JohnTitor Nov 16, 2021
f5dc388
Point at source of trait bound obligations in more places
estebank Oct 5, 2021
3fe48b2
Change `trait_defs.rs` incremental hash test
estebank Oct 6, 2021
412793f
Point at bounds when comparing impl items to trait
estebank Oct 6, 2021
abf70a9
Do not mention associated items when they introduce an obligation
estebank Oct 12, 2021
a6b31eb
Align multiline messages to their label (add left margin)
estebank Oct 13, 2021
70e8240
Point at `impl` blocks when they introduce unmet obligations
estebank Oct 13, 2021
8d443ea
Suggest constraining `fn` type params when appropriate
estebank Oct 13, 2021
1cadfe6
Move tests for missing trait bounds to their own directory
estebank Oct 14, 2021
2c173af
review comments
estebank Nov 18, 2021
a8dcc87
Move tests from ui directory
estebank Nov 18, 2021
2f1a1f5
fix CTFE/Miri simd_insert/extract on array-style repr(simd) types
RalfJung Nov 18, 2021
0304e16
CTFE SIMD: also test 1-element array
RalfJung Nov 18, 2021
214ad2f
rustdoc doctest: detect `fn main` after an unexpected semicolon
notriddle Nov 18, 2021
592178c
Put back removed empty line
GuillaumeGomez Nov 19, 2021
cdb0c29
Remove unnecessary doc links
WaffleLapkin Nov 19, 2021
a2d7857
Turn all 0x1b_u8 into '\x1b' or b'\x1b'
wooster0 Nov 19, 2021
0ae053a
rustdoc: Fix some unescaped HTML tags in docs
camelid Nov 19, 2021
6df0106
Rollup merge of #88361 - WaffleLapkin:patch-2, r=jyn514
matthiaskrgr Nov 19, 2021
de4775f
Rollup merge of #89580 - estebank:trait-bounds-are-tricky, r=nagisa
matthiaskrgr Nov 19, 2021
79eeb69
Rollup merge of #90956 - JohnTitor:issue-87573, r=Mark-Simulacrum
matthiaskrgr Nov 19, 2021
0ecf096
Rollup merge of #90999 - RalfJung:miri_simd, r=oli-obk
matthiaskrgr Nov 19, 2021
b01e807
Rollup merge of #91026 - notriddle:notriddle/rustdoc-doctest-semicolo…
matthiaskrgr Nov 19, 2021
f0e2042
Rollup merge of #91035 - GuillaumeGomez:put-back-removed-empty-line, …
matthiaskrgr Nov 19, 2021
774a884
Rollup merge of #91044 - r00ster91:x1b, r=joshtriplett
matthiaskrgr Nov 19, 2021
e47fe9c
Rollup merge of #91054 - camelid:fix-tags, r=GuillaumeGomez
matthiaskrgr Nov 19, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Point at impl blocks when they introduce unmet obligations
Group obligations by `impl` block that introduced them.
  • Loading branch information
estebank committed Nov 18, 2021
commit 70e8240a95d26cc6d08097ab8a8e657222c2ee8a
10 changes: 8 additions & 2 deletions compiler/rustc_typeck/src/check/method/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub use self::CandidateSource::*;
pub use self::MethodError::*;

use crate::check::FnCtxt;
use crate::ObligationCause;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
Expand Down Expand Up @@ -71,7 +72,8 @@ pub enum MethodError<'tcx> {
#[derive(Debug)]
pub struct NoMatchData<'tcx> {
pub static_candidates: Vec<CandidateSource>,
pub unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
pub unsatisfied_predicates:
Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
pub out_of_scope_traits: Vec<DefId>,
pub lev_candidate: Option<ty::AssocItem>,
pub mode: probe::Mode,
Expand All @@ -80,7 +82,11 @@ pub struct NoMatchData<'tcx> {
impl<'tcx> NoMatchData<'tcx> {
pub fn new(
static_candidates: Vec<CandidateSource>,
unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
unsatisfied_predicates: Vec<(
ty::Predicate<'tcx>,
Option<ty::Predicate<'tcx>>,
Option<ObligationCause<'tcx>>,
)>,
out_of_scope_traits: Vec<DefId>,
lev_candidate: Option<ty::AssocItem>,
mode: probe::Mode,
Expand Down
26 changes: 18 additions & 8 deletions compiler/rustc_typeck/src/check/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ struct ProbeContext<'a, 'tcx> {

/// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
/// for error reporting
unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
unsatisfied_predicates:
Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,

is_suggestion: IsSuggestion,

Expand Down Expand Up @@ -1268,6 +1269,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
possibly_unsatisfied_predicates: &mut Vec<(
ty::Predicate<'tcx>,
Option<ty::Predicate<'tcx>>,
Option<ObligationCause<'tcx>>,
)>,
unstable_candidates: Option<&mut Vec<(&'b Candidate<'tcx>, Symbol)>>,
) -> Option<PickResult<'tcx>>
Expand Down Expand Up @@ -1412,6 +1414,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
possibly_unsatisfied_predicates: &mut Vec<(
ty::Predicate<'tcx>,
Option<ty::Predicate<'tcx>>,
Option<ObligationCause<'tcx>>,
)>,
) -> ProbeResult {
debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe);
Expand All @@ -1423,8 +1426,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
.sup(probe.xform_self_ty, self_ty)
{
Ok(InferOk { obligations, value: () }) => obligations,
Err(_) => {
debug!("--> cannot relate self-types");
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
return ProbeResult::NoMatch;
}
};
Expand Down Expand Up @@ -1473,7 +1476,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let o = self.resolve_vars_if_possible(o);
if !self.predicate_may_hold(&o) {
result = ProbeResult::NoMatch;
possibly_unsatisfied_predicates.push((o.predicate, None));
possibly_unsatisfied_predicates.push((
o.predicate,
None,
Some(o.cause),
));
}
}
}
Expand Down Expand Up @@ -1519,16 +1526,19 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
} else {
Some(predicate)
};
possibly_unsatisfied_predicates
.push((nested_predicate, p));
possibly_unsatisfied_predicates.push((
nested_predicate,
p,
Some(obligation.cause.clone()),
));
}
}
}
_ => {
// Some nested subobligation of this predicate
// failed.
let predicate = self.resolve_vars_if_possible(predicate);
possibly_unsatisfied_predicates.push((predicate, None));
possibly_unsatisfied_predicates.push((predicate, None, None));
}
}
false
Expand All @@ -1547,7 +1557,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let o = self.resolve_vars_if_possible(o);
if !self.predicate_may_hold(&o) {
result = ProbeResult::NoMatch;
possibly_unsatisfied_predicates.push((o.predicate, None));
possibly_unsatisfied_predicates.push((o.predicate, None, Some(o.cause)));
}
}

Expand Down
116 changes: 105 additions & 11 deletions compiler/rustc_typeck/src/check/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ use rustc_span::lev_distance;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{FulfillmentError, Obligation};
use rustc_trait_selection::traits::{
FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
};

use std::cmp::Ordering;
use std::iter;
Expand Down Expand Up @@ -787,9 +789,88 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => None,
}
};

// Find all the requirements that come from a local `impl` block.
let mut skip_list: FxHashSet<_> = Default::default();
let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
for (data, p, parent_p) in unsatisfied_predicates
.iter()
.filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
.filter_map(|(p, parent, c)| match c.code {
ObligationCauseCode::ImplDerivedObligation(ref data) => {
Some((data, p, parent))
}
_ => None,
})
{
let parent_trait_ref = data.parent_trait_ref;
let parent_def_id = parent_trait_ref.def_id();
let path = parent_trait_ref.print_only_trait_path();
let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
let mut candidates = vec![];
self.tcx.for_each_relevant_impl(
parent_def_id,
parent_trait_ref.self_ty().skip_binder(),
|impl_def_id| match self.tcx.hir().get_if_local(impl_def_id) {
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { .. }),
..
})) => {
candidates.push(impl_def_id);
}
_ => {}
},
);
if let [def_id] = &candidates[..] {
match self.tcx.hir().get_if_local(*def_id) {
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
..
})) => {
if let Some(pred) = parent_p {
// Done to add the "doesn't satisfy" `span_label`.
let _ = format_pred(*pred);
}
skip_list.insert(p);
let mut spans = Vec::with_capacity(2);
if let Some(trait_ref) = of_trait {
spans.push(trait_ref.path.span);
}
spans.push(self_ty.span);
let entry = spanned_predicates.entry(spans.into());
entry
.or_insert_with(|| (path, tr_self_ty, Vec::new()))
.2
.push(p);
}
_ => {}
}
}
}
for (span, (path, self_ty, preds)) in spanned_predicates {
err.span_note(
span,
&format!(
"the following trait bounds were not satisfied because of the \
requirements of the implementation of `{}` for `{}`:\n{}",
path,
self_ty,
preds
.into_iter()
// .map(|pred| format!("{:?}", pred))
.filter_map(|pred| format_pred(*pred))
.map(|(p, _)| format!("`{}`", p))
.collect::<Vec<_>>()
.join("\n"),
),
);
}

// The requirements that didn't have an `impl` span to show.
let mut bound_list = unsatisfied_predicates
.iter()
.filter_map(|(pred, parent_pred)| {
.filter(|(pred, _, _parent_pred)| !skip_list.contains(&pred))
.filter_map(|(pred, parent_pred, _cause)| {
format_pred(*pred).map(|(p, self_ty)| match parent_pred {
None => format!("`{}`", &p),
Some(parent_pred) => match format_pred(*parent_pred) {
Expand Down Expand Up @@ -832,7 +913,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for (span, msg) in bound_spans.into_iter() {
err.span_label(span, &msg);
}
if !bound_list.is_empty() {
if !bound_list.is_empty() || !skip_list.is_empty() {
let bound_list = bound_list
.into_iter()
.map(|(_, path)| path)
Expand All @@ -842,9 +923,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.set_primary_message(&format!(
"the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
));
err.note(&format!(
"the following trait bounds were not satisfied:\n{bound_list}"
));
if !bound_list.is_empty() {
err.note(&format!(
"the following trait bounds were not satisfied:\n{bound_list}"
));
}
self.suggest_derive(&mut err, &unsatisfied_predicates);

unsatisfied_bounds = true;
Expand Down Expand Up @@ -1058,18 +1141,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_note(spans, &msg);
}

let preds: Vec<_> = errors.iter().map(|e| (e.obligation.predicate, None)).collect();
let preds: Vec<_> = errors
.iter()
.map(|e| (e.obligation.predicate, None, Some(e.obligation.cause.clone())))
.collect();
self.suggest_derive(err, &preds);
}

fn suggest_derive(
&self,
err: &mut DiagnosticBuilder<'_>,
unsatisfied_predicates: &Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
unsatisfied_predicates: &Vec<(
ty::Predicate<'tcx>,
Option<ty::Predicate<'tcx>>,
Option<ObligationCause<'tcx>>,
)>,
) {
let mut derives = Vec::<(String, Span, String)>::new();
let mut traits = Vec::<Span>::new();
for (pred, _) in unsatisfied_predicates {
for (pred, _, _) in unsatisfied_predicates {
let trait_pred = match pred.kind().skip_binder() {
ty::PredicateKind::Trait(trait_pred) => trait_pred,
_ => continue,
Expand Down Expand Up @@ -1260,7 +1350,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_name: Ident,
source: SelfSource<'tcx>,
valid_out_of_scope_traits: Vec<DefId>,
unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)],
unsatisfied_predicates: &[(
ty::Predicate<'tcx>,
Option<ty::Predicate<'tcx>>,
Option<ObligationCause<'tcx>>,
)],
unsatisfied_bounds: bool,
) {
let mut alt_rcvr_sugg = false;
Expand Down Expand Up @@ -1376,7 +1470,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// this isn't perfect (that is, there are cases when
// implementing a trait would be legal but is rejected
// here).
unsatisfied_predicates.iter().all(|(p, _)| {
unsatisfied_predicates.iter().all(|(p, _, _)| {
match p.kind().skip_binder() {
// Hide traits if they are present in predicates as they can be fixed without
// having to implement them.
Expand Down
10 changes: 7 additions & 3 deletions src/test/ui/derives/derive-assoc-type-not-impl.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,16 @@ LL | struct NotClone;
LL | Bar::<NotClone> { x: 1 }.clone();
| ^^^^^ method cannot be called on `Bar<NotClone>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`NotClone: Clone`
which is required by `Bar<NotClone>: Clone`
note: the following trait bounds were not satisfied because of the requirements of the implementation of `Clone` for `_`:
`NotClone: Clone`
--> $DIR/derive-assoc-type-not-impl.rs:6:10
|
LL | #[derive(Clone)]
| ^^^^^
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `clone`, perhaps you need to implement it:
candidate #1: `Clone`
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `NotClone` with `#[derive(Clone)]`
|
LL | #[derive(Clone)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ trait M {
}

impl<T: X<Y<i32> = i32>> M for T {}
//~^ NOTE the following trait bounds were not satisfied

struct S;
//~^ NOTE method `f` not found for this
Expand All @@ -26,7 +27,6 @@ fn f(a: S) {
a.f();
//~^ ERROR the method `f` exists for struct `S`, but its trait bounds were not satisfied
//~| NOTE method cannot be called on `S` due to unsatisfied trait bounds
//~| NOTE the following trait bounds were not satisfied:
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0599]: the method `f` exists for struct `S`, but its trait bounds were not satisfied
--> $DIR/method-unsatified-assoc-type-predicate.rs:26:7
--> $DIR/method-unsatified-assoc-type-predicate.rs:27:7
|
LL | struct S;
| ---------
Expand All @@ -11,9 +11,12 @@ LL | struct S;
LL | a.f();
| ^ method cannot be called on `S` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`<S as X>::Y<i32> = i32`
which is required by `S: M`
note: the following trait bounds were not satisfied because of the requirements of the implementation of `M` for `_`:
`<S as X>::Y<i32> = i32`
--> $DIR/method-unsatified-assoc-type-predicate.rs:14:26
|
LL | impl<T: X<Y<i32> = i32>> M for T {}
| ^ ^

error: aborting due to previous error

Expand Down
Loading