summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs')
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs79
1 files changed, 63 insertions, 16 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
index 752b53fbc..0419bb3f7 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
@@ -1,52 +1,99 @@
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 = tcx.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, predicates.into_iter()) {
+ 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
}