Skip to content

Commit 41d8c94

Browse files
committed
Auto merge of #89427 - estebank:collect-overlapping-impls, r=jackh726
Point at overlapping impls when type annotations are needed Address #89254.
2 parents 00d5e42 + 881a50c commit 41d8c94

38 files changed

+661
-116
lines changed

compiler/rustc_errors/src/diagnostic.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -465,10 +465,14 @@ impl Diagnostic {
465465
suggestions: impl Iterator<Item = String>,
466466
applicability: Applicability,
467467
) -> &mut Self {
468+
let mut suggestions: Vec<_> = suggestions.collect();
469+
suggestions.sort();
470+
let substitutions = suggestions
471+
.into_iter()
472+
.map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] })
473+
.collect();
468474
self.suggestions.push(CodeSuggestion {
469-
substitutions: suggestions
470-
.map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] })
471-
.collect(),
475+
substitutions,
472476
msg: msg.to_owned(),
473477
style: SuggestionStyle::ShowCode,
474478
applicability,

compiler/rustc_middle/src/traits/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -440,16 +440,28 @@ pub struct DerivedObligationCause<'tcx> {
440440

441441
#[derive(Clone, Debug, TypeFoldable, Lift)]
442442
pub enum SelectionError<'tcx> {
443+
/// The trait is not implemented.
443444
Unimplemented,
445+
/// After a closure impl has selected, its "outputs" were evaluated
446+
/// (which for closures includes the "input" type params) and they
447+
/// didn't resolve. See `confirm_poly_trait_refs` for more.
444448
OutputTypeParameterMismatch(
445449
ty::PolyTraitRef<'tcx>,
446450
ty::PolyTraitRef<'tcx>,
447451
ty::error::TypeError<'tcx>,
448452
),
453+
/// The trait pointed by `DefId` is not object safe.
449454
TraitNotObjectSafe(DefId),
455+
/// A given constant couldn't be evaluated.
450456
NotConstEvaluatable(NotConstEvaluatable),
457+
/// Exceeded the recursion depth during type projection.
451458
Overflow,
459+
/// Signaling that an error has already been emitted, to avoid
460+
/// multiple errors being shown.
452461
ErrorReporting,
462+
/// Multiple applicable `impl`s where found. The `DefId`s correspond to
463+
/// all the `impl`s' Items.
464+
Ambiguous(Vec<DefId>),
453465
}
454466

455467
/// When performing resolution, it is typically the case that there

compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

+152-11
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use std::iter;
3434

3535
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
3636
use crate::traits::query::normalize::AtExt as _;
37+
use crate::traits::specialize::to_pretty_impl_header;
3738
use on_unimplemented::InferCtxtExt as _;
3839
use suggestions::InferCtxtExt as _;
3940

@@ -241,6 +242,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
241242
let mut span = obligation.cause.span;
242243

243244
let mut err = match *error {
245+
SelectionError::Ambiguous(ref impls) => {
246+
let mut err = self.tcx.sess.struct_span_err(
247+
obligation.cause.span,
248+
&format!("multiple applicable `impl`s for `{}`", obligation.predicate),
249+
);
250+
self.annotate_source_of_ambiguity(&mut err, impls, obligation.predicate);
251+
err.emit();
252+
return;
253+
}
244254
SelectionError::Unimplemented => {
245255
// If this obligation was generated as a result of well-formedness checking, see if we
246256
// can get a better error message by performing HIR-based well-formedness checking.
@@ -1138,6 +1148,13 @@ trait InferCtxtPrivExt<'tcx> {
11381148
obligation: &PredicateObligation<'tcx>,
11391149
);
11401150

1151+
fn annotate_source_of_ambiguity(
1152+
&self,
1153+
err: &mut DiagnosticBuilder<'tcx>,
1154+
impls: &[DefId],
1155+
predicate: ty::Predicate<'tcx>,
1156+
);
1157+
11411158
fn maybe_suggest_unsized_generics(
11421159
&self,
11431160
err: &mut DiagnosticBuilder<'tcx>,
@@ -1549,11 +1566,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
15491566
?predicate, ?obligation.cause.code,
15501567
);
15511568

1552-
// Ambiguity errors are often caused as fallout from earlier
1553-
// errors. So just ignore them if this infcx is tainted.
1554-
if self.is_tainted_by_errors() {
1555-
return;
1556-
}
1569+
// Ambiguity errors are often caused as fallout from earlier errors.
1570+
// We ignore them if this `infcx` is tainted in some cases below.
15571571

15581572
let bound_predicate = predicate.kind();
15591573
let mut err = match bound_predicate.skip_binder() {
@@ -1601,10 +1615,19 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
16011615
// check upstream for type errors and don't add the obligations to
16021616
// begin with in those cases.
16031617
if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
1604-
self.emit_inference_failure_err(body_id, span, subst, vec![], ErrorCode::E0282)
1618+
if !self.is_tainted_by_errors() {
1619+
self.emit_inference_failure_err(
1620+
body_id,
1621+
span,
1622+
subst,
1623+
vec![],
1624+
ErrorCode::E0282,
1625+
)
16051626
.emit();
1627+
}
16061628
return;
16071629
}
1630+
16081631
let impl_candidates = self.find_similar_impl_candidates(trait_ref);
16091632
let mut err = self.emit_inference_failure_err(
16101633
body_id,
@@ -1613,7 +1636,29 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
16131636
impl_candidates,
16141637
ErrorCode::E0283,
16151638
);
1616-
err.note(&format!("cannot satisfy `{}`", predicate));
1639+
1640+
let obligation = Obligation::new(
1641+
obligation.cause.clone(),
1642+
obligation.param_env,
1643+
trait_ref.to_poly_trait_predicate(),
1644+
);
1645+
let mut selcx = SelectionContext::with_query_mode(
1646+
&self,
1647+
crate::traits::TraitQueryMode::Standard,
1648+
);
1649+
match selcx.select_from_obligation(&obligation) {
1650+
Err(SelectionError::Ambiguous(impls)) if impls.len() > 1 => {
1651+
self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
1652+
}
1653+
_ => {
1654+
if self.is_tainted_by_errors() {
1655+
err.cancel();
1656+
return;
1657+
}
1658+
err.note(&format!("cannot satisfy `{}`", predicate));
1659+
}
1660+
}
1661+
16171662
if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code {
16181663
self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
16191664
} else if let (
@@ -1674,15 +1719,21 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
16741719
ty::PredicateKind::WellFormed(arg) => {
16751720
// Same hacky approach as above to avoid deluging user
16761721
// with error messages.
1677-
if arg.references_error() || self.tcx.sess.has_errors() {
1722+
if arg.references_error()
1723+
|| self.tcx.sess.has_errors()
1724+
|| self.is_tainted_by_errors()
1725+
{
16781726
return;
16791727
}
16801728

16811729
self.emit_inference_failure_err(body_id, span, arg, vec![], ErrorCode::E0282)
16821730
}
16831731

16841732
ty::PredicateKind::Subtype(data) => {
1685-
if data.references_error() || self.tcx.sess.has_errors() {
1733+
if data.references_error()
1734+
|| self.tcx.sess.has_errors()
1735+
|| self.is_tainted_by_errors()
1736+
{
16861737
// no need to overload user in such cases
16871738
return;
16881739
}
@@ -1694,7 +1745,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
16941745
ty::PredicateKind::Projection(data) => {
16951746
let self_ty = data.projection_ty.self_ty();
16961747
let ty = data.ty;
1697-
if predicate.references_error() {
1748+
if predicate.references_error() || self.is_tainted_by_errors() {
16981749
return;
16991750
}
17001751
if self_ty.needs_infer() && ty.needs_infer() {
@@ -1722,7 +1773,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
17221773
}
17231774

17241775
_ => {
1725-
if self.tcx.sess.has_errors() {
1776+
if self.tcx.sess.has_errors() || self.is_tainted_by_errors() {
17261777
return;
17271778
}
17281779
let mut err = struct_span_err!(
@@ -1740,6 +1791,96 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
17401791
err.emit();
17411792
}
17421793

1794+
fn annotate_source_of_ambiguity(
1795+
&self,
1796+
err: &mut DiagnosticBuilder<'tcx>,
1797+
impls: &[DefId],
1798+
predicate: ty::Predicate<'tcx>,
1799+
) {
1800+
let mut spans = vec![];
1801+
let mut crates = vec![];
1802+
let mut post = vec![];
1803+
for def_id in impls {
1804+
match self.tcx.span_of_impl(*def_id) {
1805+
Ok(span) => spans.push(self.tcx.sess.source_map().guess_head_span(span)),
1806+
Err(name) => {
1807+
crates.push(name);
1808+
if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) {
1809+
post.push(header);
1810+
}
1811+
}
1812+
}
1813+
}
1814+
let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
1815+
let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
1816+
crate_names.sort();
1817+
crate_names.dedup();
1818+
post.sort();
1819+
post.dedup();
1820+
1821+
if self.is_tainted_by_errors()
1822+
&& crate_names.len() == 1
1823+
&& crate_names[0] == "`core`"
1824+
&& spans.len() == 0
1825+
{
1826+
// Avoid complaining about other inference issues for expressions like
1827+
// `42 >> 1`, where the types are still `{integer}`, but we want to
1828+
// Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too?
1829+
err.cancel();
1830+
return;
1831+
}
1832+
let post = if post.len() > 4 {
1833+
format!(
1834+
":\n{}\nand {} more",
1835+
post.iter().map(|p| format!("- {}", p)).take(4).collect::<Vec<_>>().join("\n"),
1836+
post.len() - 4,
1837+
)
1838+
} else if post.len() > 1 || (post.len() == 1 && post[0].contains("\n")) {
1839+
format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),)
1840+
} else if post.len() == 1 {
1841+
format!(": `{}`", post[0])
1842+
} else {
1843+
String::new()
1844+
};
1845+
1846+
match (spans.len(), crates.len(), crate_names.len()) {
1847+
(0, 0, 0) => {
1848+
err.note(&format!("cannot satisfy `{}`", predicate));
1849+
}
1850+
(0, _, 1) => {
1851+
err.note(&format!("{} in the `{}` crate{}", msg, crates[0], post,));
1852+
}
1853+
(0, _, _) => {
1854+
err.note(&format!(
1855+
"{} in the following crates: {}{}",
1856+
msg,
1857+
crate_names.join(", "),
1858+
post,
1859+
));
1860+
}
1861+
(_, 0, 0) => {
1862+
let span: MultiSpan = spans.into();
1863+
err.span_note(span, &msg);
1864+
}
1865+
(_, 1, 1) => {
1866+
let span: MultiSpan = spans.into();
1867+
err.span_note(span, &msg);
1868+
err.note(
1869+
&format!("and another `impl` found in the `{}` crate{}", crates[0], post,),
1870+
);
1871+
}
1872+
_ => {
1873+
let span: MultiSpan = spans.into();
1874+
err.span_note(span, &msg);
1875+
err.note(&format!(
1876+
"and more `impl`s found in the following crates: {}{}",
1877+
crate_names.join(", "),
1878+
post,
1879+
));
1880+
}
1881+
}
1882+
}
1883+
17431884
/// Returns `true` if the trait predicate may apply for *some* assignment
17441885
/// to the type parameters.
17451886
fn predicate_can_apply(

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+9-12
Original file line numberDiff line numberDiff line change
@@ -299,18 +299,15 @@ fn suggest_restriction(
299299
generics,
300300
trait_ref.without_const().to_predicate(tcx).to_string(),
301301
),
302-
(None, Some((ident, []))) => (
303-
ident.span.shrink_to_hi(),
304-
format!(": {}", trait_ref.print_only_trait_path().to_string()),
305-
),
306-
(_, Some((_, [.., bounds]))) => (
307-
bounds.span().shrink_to_hi(),
308-
format!(" + {}", trait_ref.print_only_trait_path().to_string()),
309-
),
310-
(Some(_), Some((_, []))) => (
311-
generics.span.shrink_to_hi(),
312-
format!(": {}", trait_ref.print_only_trait_path().to_string()),
313-
),
302+
(None, Some((ident, []))) => {
303+
(ident.span.shrink_to_hi(), format!(": {}", trait_ref.print_only_trait_path()))
304+
}
305+
(_, Some((_, [.., bounds]))) => {
306+
(bounds.span().shrink_to_hi(), format!(" + {}", trait_ref.print_only_trait_path()))
307+
}
308+
(Some(_), Some((_, []))) => {
309+
(generics.span.shrink_to_hi(), format!(": {}", trait_ref.print_only_trait_path()))
310+
}
314311
};
315312

316313
err.span_suggestion_verbose(

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::traits;
1818
use crate::traits::coherence::Conflict;
1919
use crate::traits::query::evaluate_obligation::InferCtxtExt;
2020
use crate::traits::{util, SelectionResult};
21-
use crate::traits::{ErrorReporting, Overflow, Unimplemented};
21+
use crate::traits::{Ambiguous, ErrorReporting, Overflow, Unimplemented};
2222

2323
use super::BuiltinImplConditions;
2424
use super::IntercrateAmbiguityCause;
@@ -197,7 +197,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
197197
// and report ambiguity.
198198
if i > 1 {
199199
debug!("multiple matches, ambig");
200-
return Ok(None);
200+
return Err(Ambiguous(
201+
candidates
202+
.into_iter()
203+
.filter_map(|c| match c.candidate {
204+
SelectionCandidate::ImplCandidate(def_id) => Some(def_id),
205+
_ => None,
206+
})
207+
.collect(),
208+
));
201209
}
202210
}
203211
}

compiler/rustc_trait_selection/src/traits/select/mod.rs

+17-6
Original file line numberDiff line numberDiff line change
@@ -357,18 +357,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
357357
&mut self,
358358
obligation: &TraitObligation<'tcx>,
359359
) -> SelectionResult<'tcx, Selection<'tcx>> {
360-
debug_assert!(!obligation.predicate.has_escaping_bound_vars());
361-
362-
let pec = &ProvisionalEvaluationCache::default();
363-
let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
364-
365-
let candidate = match self.candidate_from_obligation(&stack) {
360+
let candidate = match self.select_from_obligation(obligation) {
366361
Err(SelectionError::Overflow) => {
367362
// In standard mode, overflow must have been caught and reported
368363
// earlier.
369364
assert!(self.query_mode == TraitQueryMode::Canonical);
370365
return Err(SelectionError::Overflow);
371366
}
367+
Err(SelectionError::Ambiguous(_)) => {
368+
return Ok(None);
369+
}
372370
Err(e) => {
373371
return Err(e);
374372
}
@@ -391,6 +389,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
391389
}
392390
}
393391

392+
crate fn select_from_obligation(
393+
&mut self,
394+
obligation: &TraitObligation<'tcx>,
395+
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
396+
debug_assert!(!obligation.predicate.has_escaping_bound_vars());
397+
398+
let pec = &ProvisionalEvaluationCache::default();
399+
let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
400+
401+
self.candidate_from_obligation(&stack)
402+
}
403+
394404
///////////////////////////////////////////////////////////////////////////
395405
// EVALUATION
396406
//
@@ -915,6 +925,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
915925

916926
match self.candidate_from_obligation(stack) {
917927
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
928+
Err(SelectionError::Ambiguous(_)) => Ok(EvaluatedToAmbig),
918929
Ok(None) => Ok(EvaluatedToAmbig),
919930
Err(Overflow) => Err(OverflowError::Canonical),
920931
Err(ErrorReporting) => Err(OverflowError::ErrorReporting),

0 commit comments

Comments
 (0)