Skip to content

Commit 397b66e

Browse files
committed
Auto merge of #105285 - compiler-errors:conflicting-param-env-2, r=estebank
Highlight conflicting param-env candidates, again Un-reverts #98794 (i.e. reverts #99290). The previous time I attempted to land this PR, it was because of an incremental issue (#99233). The repro instructions in the issue is no longer manifest the ICE -- I think it's because this ambiguity code was refactored (I think by `@lcnr)` to no longer store the ambiguities in the fulfillment error, but instead recompute them on the fly. The main motivation for trying to re-land this is that it fixes #105131 by highlighting the root-cause of the issue, which is conflicting param-env candidates: ``` error[E0283]: type annotations needed: cannot satisfy `Self: Gen<'source>` | note: multiple `impl`s or `where` clauses satisfying `Self: Gen<'source>` found --> $DIR/conflicting-bounds.rs:3:1 | LL | pub trait Gen<'source> { | ^^^^^^^^^^^^^^^^^^^^^^ ... LL | Self: for<'s> Gen<'s, Output = T>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error For more information about this error, try `rustc --explain E0283`. ``` Fixes #105131. Fixes (again) #98786
2 parents d67000e + d10f6b4 commit 397b66e

File tree

10 files changed

+183
-41
lines changed

10 files changed

+183
-41
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,101 @@
11
use rustc_hir::def_id::DefId;
2-
use rustc_infer::infer::InferCtxt;
2+
use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime};
3+
use rustc_infer::traits::util::elaborate_predicates_with_span;
34
use rustc_infer::traits::{Obligation, ObligationCause, TraitObligation};
4-
use rustc_span::DUMMY_SP;
5+
use rustc_middle::ty;
6+
use rustc_span::{Span, DUMMY_SP};
57

68
use crate::traits::ObligationCtxt;
79

10+
pub enum Ambiguity {
11+
DefId(DefId),
12+
ParamEnv(Span),
13+
}
14+
815
pub fn recompute_applicable_impls<'tcx>(
916
infcx: &InferCtxt<'tcx>,
1017
obligation: &TraitObligation<'tcx>,
11-
) -> Vec<DefId> {
18+
) -> Vec<Ambiguity> {
1219
let tcx = infcx.tcx;
1320
let param_env = obligation.param_env;
14-
let dummy_cause = ObligationCause::dummy();
21+
1522
let impl_may_apply = |impl_def_id| {
1623
let ocx = ObligationCtxt::new_in_snapshot(infcx);
1724
let placeholder_obligation =
1825
infcx.replace_bound_vars_with_placeholders(obligation.predicate);
1926
let obligation_trait_ref =
20-
ocx.normalize(&dummy_cause, param_env, placeholder_obligation.trait_ref);
27+
ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref);
2128

2229
let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
2330
let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap().subst(tcx, impl_substs);
2431
let impl_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref);
2532

26-
if let Err(_) = ocx.eq(&dummy_cause, param_env, obligation_trait_ref, impl_trait_ref) {
33+
if let Err(_) =
34+
ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, impl_trait_ref)
35+
{
2736
return false;
2837
}
2938

3039
let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs);
31-
ocx.register_obligations(
32-
impl_predicates
33-
.predicates
34-
.iter()
35-
.map(|&predicate| Obligation::new(tcx, dummy_cause.clone(), param_env, predicate)),
40+
ocx.register_obligations(impl_predicates.predicates.iter().map(|&predicate| {
41+
Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
42+
}));
43+
44+
ocx.select_where_possible().is_empty()
45+
};
46+
47+
let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| {
48+
let ocx = ObligationCtxt::new_in_snapshot(infcx);
49+
let placeholder_obligation =
50+
infcx.replace_bound_vars_with_placeholders(obligation.predicate);
51+
let obligation_trait_ref =
52+
ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref);
53+
54+
let param_env_predicate = infcx.replace_bound_vars_with_fresh_vars(
55+
DUMMY_SP,
56+
LateBoundRegionConversionTime::HigherRankedType,
57+
poly_trait_predicate,
3658
);
59+
let param_env_trait_ref =
60+
ocx.normalize(&ObligationCause::dummy(), param_env, param_env_predicate.trait_ref);
61+
62+
if let Err(_) =
63+
ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, param_env_trait_ref)
64+
{
65+
return false;
66+
}
3767

3868
ocx.select_where_possible().is_empty()
3969
};
4070

41-
let mut impls = Vec::new();
71+
let mut ambiguities = Vec::new();
72+
4273
tcx.for_each_relevant_impl(
4374
obligation.predicate.def_id(),
4475
obligation.predicate.skip_binder().trait_ref.self_ty(),
4576
|impl_def_id| {
46-
if infcx.probe(move |_snapshot| impl_may_apply(impl_def_id)) {
47-
impls.push(impl_def_id)
77+
if infcx.probe(|_| impl_may_apply(impl_def_id)) {
78+
ambiguities.push(Ambiguity::DefId(impl_def_id))
4879
}
4980
},
5081
);
51-
impls
82+
83+
let predicates =
84+
tcx.predicates_of(obligation.cause.body_id.owner.to_def_id()).instantiate_identity(tcx);
85+
for obligation in
86+
elaborate_predicates_with_span(tcx, std::iter::zip(predicates.predicates, predicates.spans))
87+
{
88+
let kind = obligation.predicate.kind();
89+
if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder()
90+
&& param_env_candidate_may_apply(kind.rebind(trait_pred))
91+
{
92+
if kind.rebind(trait_pred.trait_ref) == ty::TraitRef::identity(tcx, trait_pred.def_id()) {
93+
ambiguities.push(Ambiguity::ParamEnv(tcx.def_span(trait_pred.def_id())))
94+
} else {
95+
ambiguities.push(Ambiguity::ParamEnv(obligation.cause.span))
96+
}
97+
}
98+
}
99+
100+
ambiguities
52101
}

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

+35-13
Original file line numberDiff line numberDiff line change
@@ -1487,7 +1487,7 @@ trait InferCtxtPrivExt<'tcx> {
14871487
fn annotate_source_of_ambiguity(
14881488
&self,
14891489
err: &mut Diagnostic,
1490-
impls: &[DefId],
1490+
impls: &[ambiguity::Ambiguity],
14911491
predicate: ty::Predicate<'tcx>,
14921492
);
14931493

@@ -2180,13 +2180,22 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
21802180
let mut selcx = SelectionContext::new(&self);
21812181
match selcx.select_from_obligation(&obligation) {
21822182
Ok(None) => {
2183-
let impls = ambiguity::recompute_applicable_impls(self.infcx, &obligation);
2183+
let ambiguities =
2184+
ambiguity::recompute_applicable_impls(self.infcx, &obligation);
21842185
let has_non_region_infer =
21852186
trait_ref.skip_binder().substs.types().any(|t| !t.is_ty_infer());
21862187
// It doesn't make sense to talk about applicable impls if there are more
21872188
// than a handful of them.
2188-
if impls.len() > 1 && impls.len() < 10 && has_non_region_infer {
2189-
self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
2189+
if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
2190+
if self.tainted_by_errors().is_some() && subst.is_none() {
2191+
// If `subst.is_none()`, then this is probably two param-env
2192+
// candidates or impl candidates that are equal modulo lifetimes.
2193+
// Therefore, if we've already emitted an error, just skip this
2194+
// one, since it's not particularly actionable.
2195+
err.cancel();
2196+
return;
2197+
}
2198+
self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate);
21902199
} else {
21912200
if self.tainted_by_errors().is_some() {
21922201
err.cancel();
@@ -2434,21 +2443,30 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
24342443
fn annotate_source_of_ambiguity(
24352444
&self,
24362445
err: &mut Diagnostic,
2437-
impls: &[DefId],
2446+
ambiguities: &[ambiguity::Ambiguity],
24382447
predicate: ty::Predicate<'tcx>,
24392448
) {
24402449
let mut spans = vec![];
24412450
let mut crates = vec![];
24422451
let mut post = vec![];
2443-
for def_id in impls {
2444-
match self.tcx.span_of_impl(*def_id) {
2445-
Ok(span) => spans.push(span),
2446-
Err(name) => {
2447-
crates.push(name);
2448-
if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) {
2449-
post.push(header);
2452+
let mut has_param_env = false;
2453+
for ambiguity in ambiguities {
2454+
match ambiguity {
2455+
ambiguity::Ambiguity::DefId(impl_def_id) => {
2456+
match self.tcx.span_of_impl(*impl_def_id) {
2457+
Ok(span) => spans.push(span),
2458+
Err(name) => {
2459+
crates.push(name);
2460+
if let Some(header) = to_pretty_impl_header(self.tcx, *impl_def_id) {
2461+
post.push(header);
2462+
}
2463+
}
24502464
}
24512465
}
2466+
ambiguity::Ambiguity::ParamEnv(span) => {
2467+
has_param_env = true;
2468+
spans.push(*span);
2469+
}
24522470
}
24532471
}
24542472
let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
@@ -2472,7 +2490,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
24722490
return;
24732491
}
24742492

2475-
let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
2493+
let msg = format!(
2494+
"multiple `impl`s{} satisfying `{}` found",
2495+
if has_param_env { " or `where` clauses" } else { "" },
2496+
predicate
2497+
);
24762498
let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
24772499
format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),)
24782500
} else if post.len() == 1 {

src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr

+22-4
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,35 @@ error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual<I, 8>: True
4040
LL | IsLessOrEqual<I, 8>: True,
4141
| ^^^^
4242
|
43-
= note: cannot satisfy `IsLessOrEqual<I, 8>: True`
44-
= help: the trait `True` is implemented for `IsLessOrEqual<LHS, RHS>`
43+
note: multiple `impl`s or `where` clauses satisfying `IsLessOrEqual<I, 8>: True` found
44+
--> $DIR/issue-72787.rs:10:1
45+
|
46+
LL | impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> where
47+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
48+
...
49+
LL | IsLessOrEqual<I, 8>: True,
50+
| ^^^^
51+
...
52+
LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
53+
| ^^^^
4554

4655
error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual<I, 8>: True`
4756
--> $DIR/issue-72787.rs:21:26
4857
|
4958
LL | IsLessOrEqual<I, 8>: True,
5059
| ^^^^
5160
|
52-
= note: cannot satisfy `IsLessOrEqual<I, 8>: True`
53-
= help: the trait `True` is implemented for `IsLessOrEqual<LHS, RHS>`
61+
note: multiple `impl`s or `where` clauses satisfying `IsLessOrEqual<I, 8>: True` found
62+
--> $DIR/issue-72787.rs:10:1
63+
|
64+
LL | impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> where
65+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66+
...
67+
LL | IsLessOrEqual<I, 8>: True,
68+
| ^^^^
69+
...
70+
LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
71+
| ^^^^
5472

5573
error: aborting due to 6 previous errors
5674

src/test/ui/issues/issue-21974.stderr

+7-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ error[E0283]: type annotations needed: cannot satisfy `&'a T: Foo`
44
LL | where &'a T : Foo,
55
| ^^^
66
|
7-
= note: cannot satisfy `&'a T: Foo`
7+
note: multiple `impl`s or `where` clauses satisfying `&'a T: Foo` found
8+
--> $DIR/issue-21974.rs:11:19
9+
|
10+
LL | where &'a T : Foo,
11+
| ^^^
12+
LL | &'b T : Foo
13+
| ^^^
814

915
error: aborting due to previous error
1016

src/test/ui/issues/issue-24424.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ error[E0283]: type annotations needed: cannot satisfy `T0: Trait0<'l0>`
44
LL | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {}
55
| ^^^^^^^^^^^
66
|
7-
= note: cannot satisfy `T0: Trait0<'l0>`
7+
note: multiple `impl`s or `where` clauses satisfying `T0: Trait0<'l0>` found
8+
--> $DIR/issue-24424.rs:4:57
9+
|
10+
LL | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {}
11+
| ^^^^^^^^^^^ ^^^^^^^^^^^
812

913
error: aborting due to previous error
1014

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//~ type annotations needed: cannot satisfy `Self: Gen<'source>`
2+
3+
pub trait Gen<'source> {
4+
type Output;
5+
6+
fn gen<T>(&self) -> T
7+
where
8+
Self: for<'s> Gen<'s, Output = T>;
9+
}
10+
11+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0283]: type annotations needed: cannot satisfy `Self: Gen<'source>`
2+
|
3+
note: multiple `impl`s or `where` clauses satisfying `Self: Gen<'source>` found
4+
--> $DIR/conflicting-bounds.rs:3:1
5+
|
6+
LL | pub trait Gen<'source> {
7+
| ^^^^^^^^^^^^^^^^^^^^^^
8+
...
9+
LL | Self: for<'s> Gen<'s, Output = T>;
10+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0283`.

src/test/ui/lifetimes/issue-34979.stderr

+10-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,16 @@ error[E0283]: type annotations needed: cannot satisfy `&'a (): Foo`
44
LL | &'a (): Foo,
55
| ^^^
66
|
7-
= note: cannot satisfy `&'a (): Foo`
8-
= help: the trait `Foo` is implemented for `&'a T`
7+
note: multiple `impl`s or `where` clauses satisfying `&'a (): Foo` found
8+
--> $DIR/issue-34979.rs:2:1
9+
|
10+
LL | impl<'a, T> Foo for &'a T {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
12+
...
13+
LL | &'a (): Foo,
14+
| ^^^
15+
LL | &'static (): Foo;
16+
| ^^^
917

1018
error: aborting due to previous error
1119

src/test/ui/traits/issue-85735.stderr

+8-4
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ error[E0283]: type annotations needed: cannot satisfy `T: FnMut<(&'a (),)>`
44
LL | T: FnMut(&'a ()),
55
| ^^^^^^^^^^^^^
66
|
7-
= note: cannot satisfy `T: FnMut<(&'a (),)>`
8-
= help: the following types implement trait `FnMut<Args>`:
9-
&F
10-
&mut F
7+
note: multiple `impl`s or `where` clauses satisfying `T: FnMut<(&'a (),)>` found
8+
--> $DIR/issue-85735.rs:7:8
9+
|
10+
LL | T: FnMut(&'a ()),
11+
| ^^^^^^^^^^^^^
12+
LL |
13+
LL | T: FnMut(&'b ()),
14+
| ^^^^^^^^^^^^^
1115

1216
error: aborting due to previous error
1317

src/test/ui/type/type-check/issue-40294.stderr

+7-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ error[E0283]: type annotations needed: cannot satisfy `&'a T: Foo`
44
LL | where &'a T : Foo,
55
| ^^^
66
|
7-
= note: cannot satisfy `&'a T: Foo`
7+
note: multiple `impl`s or `where` clauses satisfying `&'a T: Foo` found
8+
--> $DIR/issue-40294.rs:6:19
9+
|
10+
LL | where &'a T : Foo,
11+
| ^^^
12+
LL | &'b T : Foo
13+
| ^^^
814

915
error: aborting due to previous error
1016

0 commit comments

Comments
 (0)