forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of rust-lang#105285 - compiler-errors:conflicting-param-…
…env-2, r=estebank Highlight conflicting param-env candidates, again Un-reverts rust-lang#98794 (i.e. reverts rust-lang#99290). The previous time I attempted to land this PR, it was because of an incremental issue (rust-lang#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 rust-lang#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 rust-lang#105131. Fixes (again) rust-lang#98786
- Loading branch information
Showing
10 changed files
with
183 additions
and
41 deletions.
There are no files selected for viewing
79 changes: 64 additions & 15 deletions
79
compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,101 @@ | ||
use rustc_hir::def_id::DefId; | ||
use rustc_infer::infer::InferCtxt; | ||
use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime}; | ||
use rustc_infer::traits::util::elaborate_predicates_with_span; | ||
use rustc_infer::traits::{Obligation, ObligationCause, TraitObligation}; | ||
use rustc_span::DUMMY_SP; | ||
use rustc_middle::ty; | ||
use rustc_span::{Span, DUMMY_SP}; | ||
|
||
use crate::traits::ObligationCtxt; | ||
|
||
pub enum Ambiguity { | ||
DefId(DefId), | ||
ParamEnv(Span), | ||
} | ||
|
||
pub fn recompute_applicable_impls<'tcx>( | ||
infcx: &InferCtxt<'tcx>, | ||
obligation: &TraitObligation<'tcx>, | ||
) -> Vec<DefId> { | ||
) -> Vec<Ambiguity> { | ||
let tcx = infcx.tcx; | ||
let param_env = obligation.param_env; | ||
let dummy_cause = ObligationCause::dummy(); | ||
|
||
let impl_may_apply = |impl_def_id| { | ||
let ocx = ObligationCtxt::new_in_snapshot(infcx); | ||
let placeholder_obligation = | ||
infcx.replace_bound_vars_with_placeholders(obligation.predicate); | ||
let obligation_trait_ref = | ||
ocx.normalize(&dummy_cause, param_env, placeholder_obligation.trait_ref); | ||
ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref); | ||
|
||
let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); | ||
let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap().subst(tcx, impl_substs); | ||
let impl_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref); | ||
|
||
if let Err(_) = ocx.eq(&dummy_cause, param_env, obligation_trait_ref, impl_trait_ref) { | ||
if let Err(_) = | ||
ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, impl_trait_ref) | ||
{ | ||
return false; | ||
} | ||
|
||
let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs); | ||
ocx.register_obligations( | ||
impl_predicates | ||
.predicates | ||
.iter() | ||
.map(|&predicate| Obligation::new(tcx, dummy_cause.clone(), param_env, predicate)), | ||
ocx.register_obligations(impl_predicates.predicates.iter().map(|&predicate| { | ||
Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate) | ||
})); | ||
|
||
ocx.select_where_possible().is_empty() | ||
}; | ||
|
||
let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| { | ||
let ocx = ObligationCtxt::new_in_snapshot(infcx); | ||
let placeholder_obligation = | ||
infcx.replace_bound_vars_with_placeholders(obligation.predicate); | ||
let obligation_trait_ref = | ||
ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref); | ||
|
||
let param_env_predicate = infcx.replace_bound_vars_with_fresh_vars( | ||
DUMMY_SP, | ||
LateBoundRegionConversionTime::HigherRankedType, | ||
poly_trait_predicate, | ||
); | ||
let param_env_trait_ref = | ||
ocx.normalize(&ObligationCause::dummy(), param_env, param_env_predicate.trait_ref); | ||
|
||
if let Err(_) = | ||
ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, param_env_trait_ref) | ||
{ | ||
return false; | ||
} | ||
|
||
ocx.select_where_possible().is_empty() | ||
}; | ||
|
||
let mut impls = Vec::new(); | ||
let mut ambiguities = Vec::new(); | ||
|
||
tcx.for_each_relevant_impl( | ||
obligation.predicate.def_id(), | ||
obligation.predicate.skip_binder().trait_ref.self_ty(), | ||
|impl_def_id| { | ||
if infcx.probe(move |_snapshot| impl_may_apply(impl_def_id)) { | ||
impls.push(impl_def_id) | ||
if infcx.probe(|_| impl_may_apply(impl_def_id)) { | ||
ambiguities.push(Ambiguity::DefId(impl_def_id)) | ||
} | ||
}, | ||
); | ||
impls | ||
|
||
let predicates = | ||
tcx.predicates_of(obligation.cause.body_id.owner.to_def_id()).instantiate_identity(tcx); | ||
for obligation in | ||
elaborate_predicates_with_span(tcx, std::iter::zip(predicates.predicates, predicates.spans)) | ||
{ | ||
let kind = obligation.predicate.kind(); | ||
if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder() | ||
&& param_env_candidate_may_apply(kind.rebind(trait_pred)) | ||
{ | ||
if kind.rebind(trait_pred.trait_ref) == ty::TraitRef::identity(tcx, trait_pred.def_id()) { | ||
ambiguities.push(Ambiguity::ParamEnv(tcx.def_span(trait_pred.def_id()))) | ||
} else { | ||
ambiguities.push(Ambiguity::ParamEnv(obligation.cause.span)) | ||
} | ||
} | ||
} | ||
|
||
ambiguities | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
//~ type annotations needed: cannot satisfy `Self: Gen<'source>` | ||
|
||
pub trait Gen<'source> { | ||
type Output; | ||
|
||
fn gen<T>(&self) -> T | ||
where | ||
Self: for<'s> Gen<'s, Output = T>; | ||
} | ||
|
||
fn main() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
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`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters