Auto merge of #91030 - estebank:trait-bounds-are-tricky-2, r=oli-obk

Properly track `ImplObligations`

Instead of probing for all possible `impl`s that could have caused an
`ImplObligation`, keep track of its `DefId` and obligation spans for
accurate error reporting.

Follow to #89580. Addresses #89418.
This commit is contained in:
bors 2022-03-24 10:24:54 +00:00
commit d2df372bca
24 changed files with 426 additions and 218 deletions

View File

@ -31,7 +31,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
// about the original obligation only.
let code = match cause.code() {
ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => &*parent_code,
_ => cause.code(),
code => code,
};
let ObligationCauseCode::MatchImpl(parent, impl_def_id) = code else {
return None;

View File

@ -257,7 +257,7 @@ pub enum ObligationCauseCode<'tcx> {
BuiltinDerivedObligation(DerivedObligationCause<'tcx>),
ImplDerivedObligation(DerivedObligationCause<'tcx>),
ImplDerivedObligation(Box<ImplDerivedObligationCause<'tcx>>),
DerivedObligation(DerivedObligationCause<'tcx>),
@ -396,16 +396,29 @@ pub enum WellFormedLoc {
},
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
pub struct ImplDerivedObligationCause<'tcx> {
pub derived: DerivedObligationCause<'tcx>,
pub impl_def_id: DefId,
pub span: Span,
}
impl ObligationCauseCode<'_> {
// Return the base obligation, ignoring derived obligations.
pub fn peel_derives(&self) -> &Self {
let mut base_cause = self;
while let BuiltinDerivedObligation(DerivedObligationCause { parent_code, .. })
| ImplDerivedObligation(DerivedObligationCause { parent_code, .. })
| DerivedObligation(DerivedObligationCause { parent_code, .. })
| FunctionArgumentObligation { parent_code, .. } = base_cause
{
base_cause = &parent_code;
loop {
match base_cause {
BuiltinDerivedObligation(DerivedObligationCause { parent_code, .. })
| DerivedObligation(DerivedObligationCause { parent_code, .. })
| FunctionArgumentObligation { parent_code, .. } => {
base_cause = &parent_code;
}
ImplDerivedObligation(obligation_cause) => {
base_cause = &*obligation_cause.derived.parent_code;
}
_ => break,
}
}
base_cause
}

View File

@ -507,8 +507,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let body_id = obligation.cause.body_id;
let span = obligation.cause.span;
let real_trait_pred = match &*code {
ObligationCauseCode::ImplDerivedObligation(cause)
| ObligationCauseCode::DerivedObligation(cause)
ObligationCauseCode::ImplDerivedObligation(cause) => cause.derived.parent_trait_pred,
ObligationCauseCode::DerivedObligation(cause)
| ObligationCauseCode::BuiltinDerivedObligation(cause) => cause.parent_trait_pred,
_ => trait_pred,
};
@ -790,8 +790,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
return false;
};
if let ObligationCauseCode::ImplDerivedObligation(obligation) = code {
try_borrowing(obligation.parent_trait_pred, &[])
if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code {
try_borrowing(cause.derived.parent_trait_pred, &[])
} else if let ObligationCauseCode::BindingObligation(_, _)
| ObligationCauseCode::ItemObligation(_) = code
{
@ -1433,13 +1433,43 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
next_code = Some(parent_code.as_ref());
}
ObligationCauseCode::ImplDerivedObligation(cause) => {
let ty = cause.derived.parent_trait_pred.skip_binder().self_ty();
debug!(
"maybe_note_obligation_cause_for_async_await: ImplDerived \
parent_trait_ref={:?} self_ty.kind={:?}",
cause.derived.parent_trait_pred,
ty.kind()
);
match *ty.kind() {
ty::Generator(did, ..) => {
generator = generator.or(Some(did));
outer_generator = Some(did);
}
ty::GeneratorWitness(..) => {}
ty::Tuple(_) if !seen_upvar_tys_infer_tuple => {
// By introducing a tuple of upvar types into the chain of obligations
// of a generator, the first non-generator item is now the tuple itself,
// we shall ignore this.
seen_upvar_tys_infer_tuple = true;
}
_ if generator.is_none() => {
trait_ref = Some(cause.derived.parent_trait_pred.skip_binder());
target_ty = Some(ty);
}
_ => {}
}
next_code = Some(cause.derived.parent_code.as_ref());
}
ObligationCauseCode::DerivedObligation(derived_obligation)
| ObligationCauseCode::BuiltinDerivedObligation(derived_obligation)
| ObligationCauseCode::ImplDerivedObligation(derived_obligation) => {
| ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) => {
let ty = derived_obligation.parent_trait_pred.skip_binder().self_ty();
debug!(
"maybe_note_obligation_cause_for_async_await: \
parent_trait_ref={:?} self_ty.kind={:?}",
parent_trait_ref={:?} self_ty.kind={:?}",
derived_obligation.parent_trait_pred,
ty.kind()
);
@ -2166,7 +2196,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}
}
ObligationCauseCode::ImplDerivedObligation(ref data) => {
let mut parent_trait_pred = self.resolve_vars_if_possible(data.parent_trait_pred);
let mut parent_trait_pred =
self.resolve_vars_if_possible(data.derived.parent_trait_pred);
parent_trait_pred.remap_constness_diag(param_env);
let parent_def_id = parent_trait_pred.def_id();
let msg = format!(
@ -2174,51 +2205,63 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
parent_trait_pred.print_modifiers_and_trait_path(),
parent_trait_pred.skip_binder().self_ty()
);
let mut candidates = vec![];
self.tcx.for_each_relevant_impl(
parent_def_id,
parent_trait_pred.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);
let mut is_auto_trait = false;
match self.tcx.hir().get_if_local(data.impl_def_id) {
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Trait(is_auto, ..),
ident,
..
})) => {
// FIXME: we should do something else so that it works even on crate foreign
// auto traits.
is_auto_trait = matches!(is_auto, hir::IsAuto::Yes);
err.span_note(ident.span, &msg)
}
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
..
})) => {
let mut spans = Vec::with_capacity(2);
if let Some(trait_ref) = of_trait {
spans.push(trait_ref.path.span);
}
_ => {}
},
);
match &candidates[..] {
[def_id] => match self.tcx.hir().get_if_local(*def_id) {
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
..
})) => {
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);
err.span_note(spans, &msg)
}
_ => err.note(&msg),
},
spans.push(self_ty.span);
err.span_note(spans, &msg)
}
_ => err.note(&msg),
};
let mut parent_predicate = parent_trait_pred.to_predicate(tcx);
let mut data = data;
let mut data = &data.derived;
let mut count = 0;
seen_requirements.insert(parent_def_id);
if is_auto_trait {
// We don't want to point at the ADT saying "required because it appears within
// the type `X`", like we would otherwise do in test `supertrait-auto-trait.rs`.
while let ObligationCauseCode::BuiltinDerivedObligation(derived) =
&*data.parent_code
{
let child_trait_ref =
self.resolve_vars_if_possible(derived.parent_trait_pred);
let child_def_id = child_trait_ref.def_id();
if seen_requirements.insert(child_def_id) {
break;
}
data = derived;
parent_predicate = child_trait_ref.to_predicate(tcx);
parent_trait_pred = child_trait_ref;
}
}
while let ObligationCauseCode::ImplDerivedObligation(child) = &*data.parent_code {
// Skip redundant recursive obligation notes. See `ui/issue-20413.rs`.
let child_trait_pred = self.resolve_vars_if_possible(child.parent_trait_pred);
let child_trait_pred =
self.resolve_vars_if_possible(child.derived.parent_trait_pred);
let child_def_id = child_trait_pred.def_id();
if seen_requirements.insert(child_def_id) {
break;
}
count += 1;
data = child;
data = &child.derived;
parent_predicate = child_trait_pred.to_predicate(tcx);
parent_trait_pred = child_trait_pred;
}

View File

@ -18,24 +18,17 @@ use rustc_span::def_id::DefId;
use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
use crate::traits::select::TraitObligationExt;
use crate::traits::util;
use crate::traits::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
use crate::traits::ImplSource;
use crate::traits::Normalized;
use crate::traits::OutputTypeParameterMismatch;
use crate::traits::Selection;
use crate::traits::TraitNotObjectSafe;
use crate::traits::VtblSegment;
use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation};
use crate::traits::util::{self, closure_trait_ref_and_return_type, predicate_for_trait_def};
use crate::traits::{
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
ImplSourceConstDestructData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
ImplSourceGeneratorData, ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
ImplSourceTraitUpcastingData, ImplSourceUserDefinedData,
BuiltinDerivedObligation, DerivedObligationCause, ImplDerivedObligation,
ImplDerivedObligationCause, ImplSource, ImplSourceAutoImplData, ImplSourceBuiltinData,
ImplSourceClosureData, ImplSourceConstDestructData, ImplSourceDiscriminantKindData,
ImplSourceFnPointerData, ImplSourceGeneratorData, ImplSourceObjectData, ImplSourcePointeeData,
ImplSourceTraitAliasData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized,
ObjectCastObligation, Obligation, ObligationCause, OutputTypeParameterMismatch,
PredicateObligation, Selection, SelectionError, TraitNotObjectSafe, TraitObligation,
Unimplemented, VtblSegment,
};
use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation};
use crate::traits::{Obligation, ObligationCause};
use crate::traits::{SelectionError, Unimplemented};
use super::BuiltinImplConditions;
use super::SelectionCandidate::{self, *};
@ -321,6 +314,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?nested, "vtable_auto_impl");
ensure_sufficient_stack(|| {
let cause = obligation.derived_cause(BuiltinDerivedObligation);
let trait_obligations: Vec<PredicateObligation<'_>> =
self.infcx.commit_unconditionally(|_| {
let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref);
self.impl_or_trait_obligations(
&cause,
obligation.recursion_depth + 1,
obligation.param_env,
trait_def_id,
&trait_ref.substs,
obligation.predicate,
)
});
let mut obligations = self.collect_predicates_for_types(
obligation.param_env,
cause,
@ -329,20 +337,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
nested,
);
let trait_obligations: Vec<PredicateObligation<'_>> =
self.infcx.commit_unconditionally(|_| {
let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref);
let cause = obligation.derived_cause(ImplDerivedObligation);
self.impl_or_trait_obligations(
cause,
obligation.recursion_depth + 1,
obligation.param_env,
trait_def_id,
&trait_ref.substs,
)
});
// Adds the predicates from the trait. Note that this contains a `Self: Trait`
// predicate as usual. It won't have any effect since auto traits are coinductive.
obligations.extend(trait_obligations);
@ -365,14 +359,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.infcx.commit_unconditionally(|_| {
let substs = self.rematch_impl(impl_def_id, obligation);
debug!(?substs, "impl substs");
let cause = obligation.derived_cause(ImplDerivedObligation);
ensure_sufficient_stack(|| {
self.vtable_impl(
impl_def_id,
substs,
cause,
&obligation.cause,
obligation.recursion_depth + 1,
obligation.param_env,
obligation.predicate,
)
})
})
@ -382,9 +376,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self,
impl_def_id: DefId,
substs: Normalized<'tcx, SubstsRef<'tcx>>,
cause: ObligationCause<'tcx>,
cause: &ObligationCause<'tcx>,
recursion_depth: usize,
param_env: ty::ParamEnv<'tcx>,
parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> {
debug!(?impl_def_id, ?substs, ?recursion_depth, "vtable_impl");
@ -394,6 +389,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
param_env,
impl_def_id,
&substs.value,
parent_trait_pred,
);
debug!(?impl_obligations, "vtable_impl");
@ -566,11 +562,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let substs = trait_ref.substs;
let trait_obligations = self.impl_or_trait_obligations(
obligation.cause.clone(),
&obligation.cause,
obligation.recursion_depth,
obligation.param_env,
trait_def_id,
&substs,
obligation.predicate,
);
debug!(?trait_def_id, ?trait_obligations, "trait alias obligations");
@ -1073,14 +1070,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
});
let substs = self.rematch_impl(impl_def_id, &new_obligation);
debug!(?substs, "impl substs");
let cause = obligation.derived_cause(ImplDerivedObligation);
let derived = DerivedObligationCause {
parent_trait_pred: obligation.predicate,
parent_code: obligation.cause.clone_code(),
};
let derived_code = ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
derived,
impl_def_id,
span: obligation.cause.span,
}));
let cause = ObligationCause::new(
obligation.cause.span,
obligation.cause.body_id,
derived_code,
);
ensure_sufficient_stack(|| {
self.vtable_impl(
impl_def_id,
substs,
cause,
&cause,
new_obligation.recursion_depth + 1,
new_obligation.param_env,
obligation.predicate,
)
})
});

View File

@ -13,15 +13,11 @@ use super::project::ProjectionTyObligation;
use super::util;
use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
use super::wf;
use super::DerivedObligationCause;
use super::Normalized;
use super::Obligation;
use super::ObligationCauseCode;
use super::Selection;
use super::SelectionResult;
use super::TraitQueryMode;
use super::{ErrorReporting, Overflow, SelectionError};
use super::{ObligationCause, PredicateObligation, TraitObligation};
use super::{
DerivedObligationCause, ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause,
Normalized, Obligation, ObligationCause, ObligationCauseCode, Overflow, PredicateObligation,
Selection, SelectionError, SelectionResult, TraitObligation, TraitQueryMode,
};
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
use crate::traits::error_reporting::InferCtxtExt;
@ -2333,11 +2329,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
#[tracing::instrument(level = "debug", skip(self, cause, param_env))]
fn impl_or_trait_obligations(
&mut self,
cause: ObligationCause<'tcx>,
cause: &ObligationCause<'tcx>,
recursion_depth: usize,
param_env: ty::ParamEnv<'tcx>,
def_id: DefId, // of impl or trait
substs: SubstsRef<'tcx>, // for impl or trait
parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
) -> Vec<PredicateObligation<'tcx>> {
let tcx = self.tcx();
@ -2359,8 +2356,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?predicates);
assert_eq!(predicates.parent, None);
let mut obligations = Vec::with_capacity(predicates.predicates.len());
for (predicate, _) in predicates.predicates {
debug!(?predicate);
let parent_code = cause.clone_code();
for (predicate, span) in predicates.predicates {
let span = *span;
let derived =
DerivedObligationCause { parent_trait_pred, parent_code: parent_code.clone() };
let code = ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
derived,
impl_def_id: def_id,
span,
}));
let cause = ObligationCause::new(cause.span, cause.body_id, code);
let predicate = normalize_with_depth_to(
self,
param_env,
@ -2369,12 +2375,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
predicate.subst(tcx, substs),
&mut obligations,
);
obligations.push(Obligation {
cause: cause.clone(),
recursion_depth,
param_env,
predicate,
});
obligations.push(Obligation { cause, recursion_depth, param_env, predicate });
}
obligations

View File

@ -227,8 +227,14 @@ fn compare_predicate_entailment<'tcx>(
traits::normalize(&mut selcx, param_env, normalize_cause, predicate);
inh.register_predicates(obligations);
let mut cause = cause.clone();
cause.span = span;
let cause = ObligationCause::new(
span,
impl_m_hir_id,
ObligationCauseCode::CompareImplMethodObligation {
impl_item_def_id: impl_m.def_id,
trait_item_def_id: trait_m.def_id,
},
);
inh.register_predicate(traits::Obligation::new(cause, param_env, predicate));
}

View File

@ -1087,8 +1087,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut result_code = code.clone();
loop {
let parent = match &*code {
ObligationCauseCode::ImplDerivedObligation(c) => {
c.derived.parent_code.clone()
}
ObligationCauseCode::BuiltinDerivedObligation(c)
| ObligationCauseCode::ImplDerivedObligation(c)
| ObligationCauseCode::DerivedObligation(c) => c.parent_code.clone(),
_ => break,
};
@ -1098,10 +1100,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
let self_: ty::subst::GenericArg<'_> = match &*unpeel_to_top(error.obligation.cause.clone_code()) {
ObligationCauseCode::BuiltinDerivedObligation(code) |
ObligationCauseCode::ImplDerivedObligation(code) |
ObligationCauseCode::DerivedObligation(code) => {
code.parent_trait_pred.self_ty().skip_binder().into()
}
ObligationCauseCode::ImplDerivedObligation(code) => {
code.derived.parent_trait_pred.self_ty().skip_binder().into()
}
_ if let ty::PredicateKind::Trait(predicate) =
error.obligation.predicate.kind().skip_binder() => {
predicate.self_ty().into()

View File

@ -1521,6 +1521,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let selcx = &mut traits::SelectionContext::new(self);
let cause = traits::ObligationCause::misc(self.span, self.body_id);
let mut parent_pred = None;
// If so, impls may carry other conditions (e.g., where
// clauses) that must be considered. Make sure that those
// match as well (or at least may match, sometimes we
@ -1584,6 +1586,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
let predicate =
ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx);
parent_pred = Some(predicate);
let obligation = traits::Obligation::new(cause, self.param_env, predicate);
if !self.predicate_may_hold(&obligation) {
result = ProbeResult::NoMatch;
@ -1639,7 +1642,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, Some(o.cause)));
possibly_unsatisfied_predicates.push((o.predicate, parent_pred, Some(o.cause)));
}
}

View File

@ -16,9 +16,8 @@ use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
use rustc_middle::ty::print::with_crate_prefix;
use rustc_middle::ty::ToPolyTraitRef;
use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_span::lev_distance;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{source_map, FileName, MultiSpan, Span};
use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, MultiSpan, Span};
use rustc_trait_selection::traits::error_reporting::on_unimplemented::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{
@ -723,102 +722,190 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// 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
for (data, p, parent_p, impl_def_id, cause_span) 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))
Some((&data.derived, p, parent, data.impl_def_id, data.span))
}
_ => None,
})
{
let parent_trait_ref = data.parent_trait_pred;
let parent_def_id = parent_trait_ref.def_id();
let path = parent_trait_ref.print_modifiers_and_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);
let unsatisfied_msg = "unsatisfied trait bound introduced here".to_string();
let derive_msg =
"unsatisfied trait bound introduced in this `derive` macro";
match self.tcx.hir().get_if_local(impl_def_id) {
// Unmet obligation comes from a `derive` macro, point at it once to
// avoid multiple span labels pointing at the same place.
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Trait(..),
ident,
..
})) if matches!(
ident.span.ctxt().outer_expn_data().kind,
ExpnKind::Macro(MacroKind::Derive, _)
) =>
{
let span = ident.span.ctxt().outer_expn_data().call_site;
let mut spans: MultiSpan = span.into();
spans.push_span_label(span, derive_msg.to_string());
let entry = spanned_predicates.entry(spans);
entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
}
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
..
})) if matches!(
self_ty.span.ctxt().outer_expn_data().kind,
ExpnKind::Macro(MacroKind::Derive, _)
) || matches!(
of_trait.as_ref().map(|t| t
.path
.span
.ctxt()
.outer_expn_data()
.kind),
Some(ExpnKind::Macro(MacroKind::Derive, _))
) =>
{
let span = self_ty.span.ctxt().outer_expn_data().call_site;
let mut spans: MultiSpan = span.into();
spans.push_span_label(span, derive_msg.to_string());
let entry = spanned_predicates.entry(spans.into());
entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
}
// Unmet obligation coming from a `trait`.
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Trait(..),
ident,
span: item_span,
..
})) if !matches!(
ident.span.ctxt().outer_expn_data().kind,
ExpnKind::Macro(MacroKind::Derive, _)
) =>
{
if let Some(pred) = parent_p {
// Done to add the "doesn't satisfy" `span_label`.
let _ = format_pred(*pred);
}
_ => {}
},
);
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);
skip_list.insert(p);
let mut spans = if cause_span != *item_span {
let mut spans: MultiSpan = cause_span.into();
spans.push_span_label(cause_span, unsatisfied_msg);
spans
} else {
ident.span.into()
};
spans.push_span_label(ident.span, "in this trait".to_string());
let entry = spanned_predicates.entry(spans.into());
entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
}
// Unmet obligation coming from an `impl`.
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
span: item_span,
..
})) if !matches!(
self_ty.span.ctxt().outer_expn_data().kind,
ExpnKind::Macro(MacroKind::Derive, _)
) && !matches!(
of_trait.as_ref().map(|t| t
.path
.span
.ctxt()
.outer_expn_data()
.kind),
Some(ExpnKind::Macro(MacroKind::Derive, _))
) =>
{
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 = if cause_span != *item_span {
let mut spans: MultiSpan = cause_span.into();
spans.push_span_label(cause_span, unsatisfied_msg);
spans
} else {
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);
spans.into()
};
if let Some(trait_ref) = of_trait {
spans.push_span_label(trait_ref.path.span, String::new());
}
_ => {}
spans.push_span_label(self_ty.span, String::new());
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"),
),
);
let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
spanned_predicates.sort_by_key(|(span, (_, _, _))| span.primary_span());
for (span, (_path, _self_ty, preds)) in spanned_predicates {
let mut preds: Vec<_> = preds
.into_iter()
.filter_map(|pred| format_pred(*pred))
.map(|(p, _)| format!("`{}`", p))
.collect();
preds.sort();
preds.dedup();
let msg = if let [pred] = &preds[..] {
format!("trait bound {} was not satisfied", pred)
} else {
format!(
"the following trait bounds were not satisfied:\n{}",
preds.join("\n"),
)
};
err.span_note(span, &msg);
unsatisfied_bounds = true;
}
// The requirements that didn't have an `impl` span to show.
let mut bound_list = unsatisfied_predicates
.iter()
.filter(|(pred, _, _parent_pred)| !skip_list.contains(&pred))
.filter_map(|(pred, parent_pred, _cause)| {
format_pred(*pred).map(|(p, self_ty)| {
collect_type_param_suggestions(self_ty, *pred, &p);
match parent_pred {
None => format!("`{}`", &p),
Some(parent_pred) => match format_pred(*parent_pred) {
(
match parent_pred {
None => format!("`{}`", &p),
Some((parent_p, _)) => {
collect_type_param_suggestions(
self_ty,
*parent_pred,
&p,
);
format!("`{}`\nwhich is required by `{}`", p, parent_p)
}
Some(parent_pred) => match format_pred(*parent_pred) {
None => format!("`{}`", &p),
Some((parent_p, _)) => {
collect_type_param_suggestions(
self_ty,
*parent_pred,
&p,
);
format!(
"`{}`\nwhich is required by `{}`",
p, parent_p
)
}
},
},
}
*pred,
)
})
})
.filter(|(_, pred)| !skip_list.contains(&pred))
.map(|(t, _)| t)
.enumerate()
.collect::<Vec<(usize, String)>>();

View File

@ -58,6 +58,7 @@ This API is completely unstable and subject to change.
#![allow(rustc::potential_query_instability)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
#![feature(crate_visibility_modifier)]
#![feature(hash_drain_filter)]

View File

@ -13,16 +13,17 @@ 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 because of the requirements of the implementation of `Clone` for `_`:
`NotClone: Clone`
note: trait bound `NotClone: Clone` was not satisfied
--> $DIR/derive-assoc-type-not-impl.rs:6:10
|
LL | #[derive(Clone)]
| ^^^^^
| ^^^^^ unsatisfied trait bound introduced in this `derive` macro
= note: the following trait bounds were not satisfied:
`NotClone: Clone`
which is required by `Bar<NotClone>: 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)]

View File

@ -12,7 +12,10 @@ trait M {
}
impl<T: X<Y<i32> = i32>> M for T {}
//~^ NOTE the following trait bounds were not satisfied
//~^ NOTE trait bound `<S as X>::Y<i32> = i32` was not satisfied
//~| NOTE unsatisfied trait bound introduced here
//~| NOTE
//~| NOTE
struct S;
//~^ NOTE method `f` not found for this

View File

@ -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:27:7
--> $DIR/method-unsatified-assoc-type-predicate.rs:30:7
|
LL | struct S;
| ---------
@ -11,12 +11,13 @@ 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 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
note: trait bound `<S as X>::Y<i32> = i32` was not satisfied
--> $DIR/method-unsatified-assoc-type-predicate.rs:14:11
|
LL | impl<T: X<Y<i32> = i32>> M for T {}
| ^ ^
| ^^^^^^^^^^^^ - -
| |
| unsatisfied trait bound introduced here
error: aborting due to previous error

View File

@ -10,14 +10,14 @@ LL | pub struct Map<S, F> {
LL | let filter = map.filterx(|x: &_| true);
| ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`:
`&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
note: the following trait bounds were not satisfied:
`&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
`&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
--> $DIR/issue-30786.rs:105:9
`&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
--> $DIR/issue-30786.rs:105:50
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| ^^^^^^^^^ ^
| --------- - ^^^^^^ unsatisfied trait bound introduced here
error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied
--> $DIR/issue-30786.rs:140:24
@ -31,14 +31,14 @@ LL | pub struct Filter<S, F> {
LL | let count = filter.countx();
| ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`:
`&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
note: the following trait bounds were not satisfied:
`&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
`&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
--> $DIR/issue-30786.rs:105:9
`&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
--> $DIR/issue-30786.rs:105:50
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| ^^^^^^^^^ ^
| --------- - ^^^^^^ unsatisfied trait bound introduced here
error: aborting due to 2 previous errors

View File

@ -10,14 +10,14 @@ LL | pub struct Map<S, F> {
LL | let filter = map.filterx(|x: &_| true);
| ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`:
`&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
note: the following trait bounds were not satisfied:
`&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
`&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
--> $DIR/issue-30786.rs:105:9
`&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
--> $DIR/issue-30786.rs:105:50
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| ^^^^^^^^^ ^
| --------- - ^^^^^^ unsatisfied trait bound introduced here
error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied
--> $DIR/issue-30786.rs:140:24
@ -31,14 +31,14 @@ LL | pub struct Filter<S, F> {
LL | let count = filter.countx();
| ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`:
`&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
note: the following trait bounds were not satisfied:
`&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
`&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
--> $DIR/issue-30786.rs:105:9
`&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
--> $DIR/issue-30786.rs:105:50
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| ^^^^^^^^^ ^
| --------- - ^^^^^^ unsatisfied trait bound introduced here
error: aborting due to 2 previous errors

View File

@ -7,11 +7,20 @@ LL | struct Foo<T> {
LL | self.foo();
| ^^^ method cannot be called on `&Foo<T>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`T: Default`
which is required by `Foo<T>: Bar`
`T: Bar`
which is required by `Foo<T>: Bar`
note: trait bound `T: Default` was not satisfied
--> $DIR/missing-trait-bounds-for-method-call.rs:10:9
|
LL | impl<T: Default + Bar> Bar for Foo<T> {}
| ^^^^^^^ --- ------
| |
| unsatisfied trait bound introduced here
note: trait bound `T: Bar` was not satisfied
--> $DIR/missing-trait-bounds-for-method-call.rs:10:19
|
LL | impl<T: Default + Bar> Bar for Foo<T> {}
| ^^^ --- ------
| |
| unsatisfied trait bound introduced here
help: consider restricting the type parameters to satisfy the trait bounds
|
LL | struct Foo<T> where T: Bar, T: Default {
@ -26,9 +35,13 @@ LL | struct Fin<T> where T: Bar {
LL | self.foo();
| ^^^ method cannot be called on `&Fin<T>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`T: Default`
which is required by `Fin<T>: Bar`
note: trait bound `T: Default` was not satisfied
--> $DIR/missing-trait-bounds-for-method-call.rs:23:9
|
LL | impl<T: Default + Bar> Bar for Fin<T> {}
| ^^^^^^^ --- ------
| |
| unsatisfied trait bound introduced here
help: consider restricting the type parameter to satisfy the trait bound
|
LL | struct Fin<T> where T: Bar, T: Default {

View File

@ -54,6 +54,12 @@ LL | const _: () = check($exp);
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `~const Destruct`
|
note: required because of the requirements on the impl of `~const Destruct` for `ConstDropImplWithBounds<NonTrivialDrop>`
--> $DIR/const-drop-fail.rs:28:25
|
LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
| ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: 1 redundant requirement hidden
= note: required because of the requirements on the impl of `~const Destruct` for `ConstDropImplWithBounds<NonTrivialDrop>`
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:34:19

View File

@ -54,6 +54,12 @@ LL | const _: () = check($exp);
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `~const Destruct`
|
note: required because of the requirements on the impl of `~const Destruct` for `ConstDropImplWithBounds<NonTrivialDrop>`
--> $DIR/const-drop-fail.rs:28:25
|
LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
| ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: 1 redundant requirement hidden
= note: required because of the requirements on the impl of `~const Destruct` for `ConstDropImplWithBounds<NonTrivialDrop>`
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:34:19

View File

@ -20,8 +20,7 @@ LL | struct MyStruct;
LL | println!("{}", MyStruct.foo_one());
| ^^^^^^^ method cannot be called on `MyStruct` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied because of the requirements of the implementation of `Foo` for `_`:
`MyStruct: Foo`
note: trait bound `MyStruct: Foo` was not satisfied
--> $DIR/specialization-trait-not-implemented.rs:14:17
|
LL | default impl<T> Foo for T {

View File

@ -5,6 +5,7 @@ LL | use_alias::<Rc<u32>>();
| ^^^^^^^ `Rc<u32>` cannot be sent between threads safely
|
= help: the trait `Send` is not implemented for `Rc<u32>`
= note: required because of the requirements on the impl of `SendSync` for `Rc<u32>`
note: required by a bound in `use_alias`
--> $DIR/cross-crate.rs:10:17
|
@ -18,6 +19,7 @@ LL | use_alias::<Rc<u32>>();
| ^^^^^^^ `Rc<u32>` cannot be shared between threads safely
|
= help: the trait `Sync` is not implemented for `Rc<u32>`
= note: required because of the requirements on the impl of `SendSync` for `Rc<u32>`
note: required by a bound in `use_alias`
--> $DIR/cross-crate.rs:10:17
|

View File

@ -14,7 +14,11 @@ LL | let (a, b) = copy(NoClone);
| |
| required by a bound introduced by this call
|
= note: required because of the requirements on the impl of `Magic` for `NoClone`
note: required because of the requirements on the impl of `Magic` for `NoClone`
--> $DIR/supertrait-auto-trait.rs:8:12
|
LL | auto trait Magic: Copy {}
| ^^^^^
note: required by a bound in `copy`
--> $DIR/supertrait-auto-trait.rs:10:12
|

View File

@ -13,6 +13,11 @@ LL | struct CloneNoCopy;
LL | let w = u.clone();
| ^^^^^ method cannot be called on `U5<CloneNoCopy>` due to unsatisfied trait bounds
|
note: trait bound `CloneNoCopy: Copy` was not satisfied
--> $DIR/union-derive-clone.rs:28:10
|
LL | #[derive(Clone, Copy)]
| ^^^^^ unsatisfied trait bound introduced in this `derive` macro
= note: the following trait bounds were not satisfied:
`CloneNoCopy: Copy`
which is required by `U5<CloneNoCopy>: Clone`

View File

@ -13,6 +13,11 @@ LL | struct CloneNoCopy;
LL | let w = u.clone();
| ^^^^^ method cannot be called on `U5<CloneNoCopy>` due to unsatisfied trait bounds
|
note: trait bound `CloneNoCopy: Copy` was not satisfied
--> $DIR/union-derive-clone.rs:28:10
|
LL | #[derive(Clone, Copy)]
| ^^^^^ unsatisfied trait bound introduced in this `derive` macro
= note: the following trait bounds were not satisfied:
`CloneNoCopy: Copy`
which is required by `U5<CloneNoCopy>: Clone`

View File

@ -5,11 +5,7 @@ LL | type IntoIter = std::iter::Flatten<std::slice::Iter<'a, T>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&T` is not an iterator
|
= help: the trait `Iterator` is not implemented for `&T`
note: required because of the requirements on the impl of `IntoIterator` for `&T`
--> $DIR/hir-wf-check-erase-regions.rs:6:29
|
LL | impl<'a, T, const N: usize> IntoIterator for &'a Table<T, N> {
| ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
= note: required because of the requirements on the impl of `IntoIterator` for `&T`
note: required by a bound in `Flatten`
--> $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL
|
@ -23,11 +19,7 @@ LL | fn into_iter(self) -> Self::IntoIter {
| ^^^^^^^^^^^^^^ `&T` is not an iterator
|
= help: the trait `Iterator` is not implemented for `&T`
note: required because of the requirements on the impl of `IntoIterator` for `&T`
--> $DIR/hir-wf-check-erase-regions.rs:6:29
|
LL | impl<'a, T, const N: usize> IntoIterator for &'a Table<T, N> {
| ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
= note: required because of the requirements on the impl of `IntoIterator` for `&T`
note: required by a bound in `Flatten`
--> $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL
|