Highlight conflicting param-env candidates
This commit is contained in:
parent
9b21131278
commit
08135254dc
@ -546,9 +546,17 @@ pub enum SelectionError<'tcx> {
|
|||||||
ErrorReporting,
|
ErrorReporting,
|
||||||
/// Multiple applicable `impl`s where found. The `DefId`s correspond to
|
/// Multiple applicable `impl`s where found. The `DefId`s correspond to
|
||||||
/// all the `impl`s' Items.
|
/// all the `impl`s' Items.
|
||||||
Ambiguous(Vec<DefId>),
|
Ambiguous(Vec<AmbiguousSelection>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum AmbiguousSelection {
|
||||||
|
Impl(DefId),
|
||||||
|
ParamEnv(Span),
|
||||||
|
}
|
||||||
|
|
||||||
|
TrivialTypeTraversalAndLiftImpls! { AmbiguousSelection, }
|
||||||
|
|
||||||
/// When performing resolution, it is typically the case that there
|
/// When performing resolution, it is typically the case that there
|
||||||
/// can be one of three outcomes:
|
/// can be one of three outcomes:
|
||||||
///
|
///
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
use rustc_hir::Item;
|
use rustc_hir::Item;
|
||||||
use rustc_hir::Node;
|
use rustc_hir::Node;
|
||||||
use rustc_infer::infer::error_reporting::same_type_modulo_infer;
|
use rustc_infer::infer::error_reporting::same_type_modulo_infer;
|
||||||
use rustc_infer::traits::TraitEngine;
|
use rustc_infer::traits::{AmbiguousSelection, TraitEngine};
|
||||||
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
|
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
|
||||||
use rustc_middle::traits::select::OverflowError;
|
use rustc_middle::traits::select::OverflowError;
|
||||||
use rustc_middle::ty::error::ExpectedFound;
|
use rustc_middle::ty::error::ExpectedFound;
|
||||||
@ -1404,7 +1404,7 @@ fn suggest_unsized_bound_if_applicable(
|
|||||||
fn annotate_source_of_ambiguity(
|
fn annotate_source_of_ambiguity(
|
||||||
&self,
|
&self,
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
impls: &[DefId],
|
impls: &[AmbiguousSelection],
|
||||||
predicate: ty::Predicate<'tcx>,
|
predicate: ty::Predicate<'tcx>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2020,6 +2020,14 @@ fn maybe_report_ambiguity(
|
|||||||
);
|
);
|
||||||
match selcx.select_from_obligation(&obligation) {
|
match selcx.select_from_obligation(&obligation) {
|
||||||
Err(SelectionError::Ambiguous(impls)) if impls.len() > 1 => {
|
Err(SelectionError::Ambiguous(impls)) if impls.len() > 1 => {
|
||||||
|
if self.is_tainted_by_errors() && subst.is_none() {
|
||||||
|
// If `subst.is_none()`, then this is probably two param-env
|
||||||
|
// candidates or impl candidates that are equal modulo lifetimes.
|
||||||
|
// Therefore, if we've already emitted an error, just skip this
|
||||||
|
// one, since it's not particularly actionable.
|
||||||
|
err.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
|
self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -2170,24 +2178,35 @@ fn maybe_report_ambiguity(
|
|||||||
fn annotate_source_of_ambiguity(
|
fn annotate_source_of_ambiguity(
|
||||||
&self,
|
&self,
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
impls: &[DefId],
|
impls: &[AmbiguousSelection],
|
||||||
predicate: ty::Predicate<'tcx>,
|
predicate: ty::Predicate<'tcx>,
|
||||||
) {
|
) {
|
||||||
let mut spans = vec![];
|
let mut spans = vec![];
|
||||||
let mut crates = vec![];
|
let mut crates = vec![];
|
||||||
let mut post = vec![];
|
let mut post = vec![];
|
||||||
for def_id in impls {
|
let mut or_where_clause = false;
|
||||||
match self.tcx.span_of_impl(*def_id) {
|
for ambig in impls {
|
||||||
Ok(span) => spans.push(span),
|
match ambig {
|
||||||
Err(name) => {
|
AmbiguousSelection::Impl(def_id) => match self.tcx.span_of_impl(*def_id) {
|
||||||
crates.push(name);
|
Ok(span) => spans.push(span),
|
||||||
if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) {
|
Err(name) => {
|
||||||
post.push(header);
|
crates.push(name);
|
||||||
|
if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) {
|
||||||
|
post.push(header);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
AmbiguousSelection::ParamEnv(span) => {
|
||||||
|
or_where_clause = true;
|
||||||
|
spans.push(*span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
|
let msg = format!(
|
||||||
|
"multiple `impl`s{} satisfying `{}` found",
|
||||||
|
if or_where_clause { " or `where` clauses" } else { "" },
|
||||||
|
predicate
|
||||||
|
);
|
||||||
let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
|
let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
|
||||||
crate_names.sort();
|
crate_names.sort();
|
||||||
crate_names.dedup();
|
crate_names.dedup();
|
||||||
|
@ -6,9 +6,11 @@
|
|||||||
//!
|
//!
|
||||||
//! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
|
//! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
|
||||||
use hir::LangItem;
|
use hir::LangItem;
|
||||||
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_infer::traits::TraitEngine;
|
use rustc_infer::traits::util::elaborate_predicates_with_span;
|
||||||
|
use rustc_infer::traits::{AmbiguousSelection, TraitEngine};
|
||||||
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
|
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
|
||||||
use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT;
|
use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT;
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
@ -199,11 +201,48 @@ fn candidate_from_obligation_no_cache<'o>(
|
|||||||
// and report ambiguity.
|
// and report ambiguity.
|
||||||
if i > 1 {
|
if i > 1 {
|
||||||
debug!("multiple matches, ambig");
|
debug!("multiple matches, ambig");
|
||||||
|
|
||||||
|
// Collect a list of (probable) spans that point to a param-env candidate
|
||||||
|
let tcx = self.infcx.tcx;
|
||||||
|
let owner = stack.obligation.cause.body_id.owner.to_def_id();
|
||||||
|
let predicates = tcx.predicates_of(owner).instantiate_identity(tcx);
|
||||||
|
let param_env_spans: FxHashMap<_, _> = elaborate_predicates_with_span(
|
||||||
|
tcx,
|
||||||
|
std::iter::zip(predicates.predicates, predicates.spans),
|
||||||
|
)
|
||||||
|
.filter_map(|obligation| {
|
||||||
|
let kind = obligation.predicate.kind();
|
||||||
|
if let ty::PredicateKind::Trait(trait_pred) = kind.skip_binder() {
|
||||||
|
if trait_pred.trait_ref
|
||||||
|
== ty::TraitRef::identity(tcx, trait_pred.def_id())
|
||||||
|
.skip_binder()
|
||||||
|
{
|
||||||
|
// HACK: Remap the `Self: Trait` predicate that every trait has to a more useful span
|
||||||
|
Some((
|
||||||
|
kind.rebind(trait_pred),
|
||||||
|
tcx.def_span(trait_pred.def_id()),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Some((kind.rebind(trait_pred), obligation.cause.span))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
return Err(Ambiguous(
|
return Err(Ambiguous(
|
||||||
candidates
|
candidates
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|c| match c.candidate {
|
.filter_map(|c| match c.candidate {
|
||||||
SelectionCandidate::ImplCandidate(def_id) => Some(def_id),
|
SelectionCandidate::ImplCandidate(def_id) => {
|
||||||
|
Some(AmbiguousSelection::Impl(def_id))
|
||||||
|
}
|
||||||
|
SelectionCandidate::ParamCandidate(predicate) => {
|
||||||
|
Some(AmbiguousSelection::ParamEnv(
|
||||||
|
*param_env_spans.get(&predicate)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -4,7 +4,13 @@ error[E0283]: type annotations needed: cannot satisfy `&'a T: Foo`
|
|||||||
LL | where &'a T : Foo,
|
LL | where &'a T : Foo,
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
|
|
||||||
= note: cannot satisfy `&'a T: Foo`
|
note: multiple `impl`s or `where` clauses satisfying `&'a T: Foo` found
|
||||||
|
--> $DIR/issue-21974.rs:11:19
|
||||||
|
|
|
||||||
|
LL | where &'a T : Foo,
|
||||||
|
| ^^^
|
||||||
|
LL | &'b T : Foo
|
||||||
|
| ^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -4,7 +4,11 @@ error[E0283]: type annotations needed: cannot satisfy `T0: Trait0<'l0>`
|
|||||||
LL | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {}
|
LL | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {}
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: cannot satisfy `T0: Trait0<'l0>`
|
note: multiple `impl`s or `where` clauses satisfying `T0: Trait0<'l0>` found
|
||||||
|
--> $DIR/issue-24424.rs:4:57
|
||||||
|
|
|
||||||
|
LL | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {}
|
||||||
|
| ^^^^^^^^^^^ ^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -4,7 +4,13 @@ error[E0283]: type annotations needed: cannot satisfy `&'a (): Foo`
|
|||||||
LL | &'a (): Foo,
|
LL | &'a (): Foo,
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
|
|
||||||
= note: cannot satisfy `&'a (): Foo`
|
note: multiple `impl`s or `where` clauses satisfying `&'a (): Foo` found
|
||||||
|
--> $DIR/issue-34979.rs:6:13
|
||||||
|
|
|
||||||
|
LL | &'a (): Foo,
|
||||||
|
| ^^^
|
||||||
|
LL | &'static (): Foo;
|
||||||
|
| ^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -4,7 +4,14 @@ error[E0283]: type annotations needed: cannot satisfy `T: FnMut<(&'a (),)>`
|
|||||||
LL | T: FnMut(&'a ()),
|
LL | T: FnMut(&'a ()),
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: cannot satisfy `T: FnMut<(&'a (),)>`
|
note: multiple `impl`s or `where` clauses satisfying `T: FnMut<(&'a (),)>` found
|
||||||
|
--> $DIR/issue-85735.rs:7:8
|
||||||
|
|
|
||||||
|
LL | T: FnMut(&'a ()),
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
LL |
|
||||||
|
LL | T: FnMut(&'b ()),
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -4,7 +4,13 @@ error[E0283]: type annotations needed: cannot satisfy `&'a T: Foo`
|
|||||||
LL | where &'a T : Foo,
|
LL | where &'a T : Foo,
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
|
|
||||||
= note: cannot satisfy `&'a T: Foo`
|
note: multiple `impl`s or `where` clauses satisfying `&'a T: Foo` found
|
||||||
|
--> $DIR/issue-40294.rs:6:19
|
||||||
|
|
|
||||||
|
LL | where &'a T : Foo,
|
||||||
|
| ^^^
|
||||||
|
LL | &'b T : Foo
|
||||||
|
| ^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user