Print more detailed trait-ref for intercrate ambiguity.

This commit is contained in:
Masaki Hara 2017-08-01 10:27:25 +04:30 committed by Niko Matsakis
parent 84bfc33fac
commit d153ff3f79
8 changed files with 49 additions and 22 deletions

View File

@ -96,25 +96,36 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
#[derive(Clone)]
pub enum IntercrateAmbiguityCause {
DownstreamCrate(DefId),
UpstreamCrateUpdate(DefId),
DownstreamCrate {
trait_desc: String,
self_desc: Option<String>,
},
UpstreamCrateUpdate {
trait_desc: String,
self_desc: Option<String>,
},
}
impl IntercrateAmbiguityCause {
/// Emits notes when the overlap is caused by complex intercrate ambiguities.
/// See #23980 for details.
pub fn add_intercrate_ambiguity_hint<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
err: &mut ::errors::DiagnosticBuilder) {
match self {
&IntercrateAmbiguityCause::DownstreamCrate(def_id) => {
err.note(&format!("downstream crates may implement `{}`",
tcx.item_path_str(def_id)));
&IntercrateAmbiguityCause::DownstreamCrate { ref trait_desc, ref self_desc } => {
let self_desc = if let &Some(ref ty) = self_desc {
format!(" for type `{}`", ty)
} else { "".to_string() };
err.note(&format!("downstream crates may implement trait `{}`{}",
trait_desc, self_desc));
}
&IntercrateAmbiguityCause::UpstreamCrateUpdate(def_id) => {
err.note(&format!("upstream crates may add new impl for `{}` \
&IntercrateAmbiguityCause::UpstreamCrateUpdate { ref trait_desc, ref self_desc } => {
let self_desc = if let &Some(ref ty) = self_desc {
format!(" for type `{}`", ty)
} else { "".to_string() };
err.note(&format!("upstream crates may add new impl of trait `{}`{} \
in future versions",
tcx.item_path_str(def_id)));
trait_desc, self_desc));
}
}
}
@ -794,9 +805,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// Heuristics: show the diagnostics when there are no candidates in crate.
if let Ok(candidate_set) = self.assemble_candidates(stack) {
if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
let did = stack.fresh_trait_ref.def_id();
self.intercrate_ambiguity_causes.push(
IntercrateAmbiguityCause::DownstreamCrate(did));
let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
let self_ty = trait_ref.self_ty();
let cause = IntercrateAmbiguityCause::DownstreamCrate {
trait_desc: trait_ref.to_string(),
self_desc: if self_ty.has_concrete_skeleton() {
Some(self_ty.to_string())
} else {
None
},
};
self.intercrate_ambiguity_causes.push(cause);
}
}
return EvaluatedToAmbig;
@ -1048,9 +1067,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// Heuristics: show the diagnostics when there are no candidates in crate.
let candidate_set = self.assemble_candidates(stack)?;
if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
let did = stack.obligation.predicate.def_id();
self.intercrate_ambiguity_causes.push(
IntercrateAmbiguityCause::UpstreamCrateUpdate(did));
let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
let self_ty = trait_ref.self_ty();
let cause = IntercrateAmbiguityCause::UpstreamCrateUpdate {
trait_desc: trait_ref.to_string(),
self_desc: if self_ty.has_concrete_skeleton() {
Some(self_ty.to_string())
} else {
None
},
};
self.intercrate_ambiguity_causes.push(cause);
}
return Ok(None);
}

View File

@ -340,7 +340,7 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
}
for cause in &overlap.intercrate_ambiguity_causes {
cause.add_intercrate_ambiguity_hint(tcx, &mut err);
cause.add_intercrate_ambiguity_hint(&mut err);
}
err.emit();

View File

@ -63,7 +63,7 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
format!("other definition for `{}`", name));
for cause in &overlap.intercrate_ambiguity_causes {
cause.add_intercrate_ambiguity_hint(self.tcx, &mut err);
cause.add_intercrate_ambiguity_hint(&mut err);
}
err.emit();

View File

@ -19,7 +19,7 @@ struct Cake<X>(X);
impl<T:Sugar> Cake<T> { fn dummy(&self) { } }
//~^ ERROR E0592
//~| NOTE duplicate definitions for `dummy`
//~| NOTE upstream crates may add new impl for `Sugar` in future versions
//~| NOTE upstream crates may add new impl of trait `Sugar` for type `std::boxed::Box<_>`
impl<U:Sugar> Cake<Box<U>> { fn dummy(&self) { } }
//~^ NOTE other definition for `dummy`

View File

@ -19,6 +19,6 @@ impl<T:Sugar> Sweet for T { }
impl<U:Sugar> Sweet for Box<U> { }
//~^ ERROR E0119
//~| NOTE conflicting implementation for `std::boxed::Box<_>`
//~| NOTE upstream crates may add new impl for `Sugar` in future versions
//~| NOTE upstream crates may add new impl of trait `Sugar` for type `std::boxed::Box<_>`
fn main() { }

View File

@ -21,7 +21,7 @@ struct A<X>(X);
impl<T> A<T> where T: Remote { fn dummy(&self) { } }
//~^ ERROR E0592
//~| NOTE duplicate definitions for `dummy`
//~| NOTE upstream crates may add new impl for `coherence_lib::Remote` in future versions
//~| NOTE upstream crates may add new impl of trait `coherence_lib::Remote` for type `i16`
impl A<i16> { fn dummy(&self) { } }
//~^ NOTE other definition for `dummy`

View File

@ -23,6 +23,6 @@ impl<T> Foo for T where T: Remote {}
impl Foo for i16 {}
//~^ ERROR E0119
//~| NOTE conflicting implementation for `i16`
//~| NOTE upstream crates may add new impl for `coherence_lib::Remote` in future versions
//~| NOTE upstream crates may add new impl of trait `coherence_lib::Remote` for type `i16`
fn main() {}

View File

@ -25,7 +25,7 @@ error[E0592]: duplicate definitions with name `baz`
43 | fn baz(&self) {}
| ---------------- other definition for `baz`
|
= note: upstream crates may add new impl for `std::marker::Copy` in future versions
= note: upstream crates may add new impl of trait `std::marker::Copy` for type `std::vec::Vec<_>` in future versions
error: aborting due to 3 previous errors