]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
Replacing bound vars is actually instantiating a binder
[rust.git] / compiler / rustc_trait_selection / src / traits / error_reporting / ambiguity.rs
1 use rustc_hir::def_id::DefId;
2 use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime};
3 use rustc_infer::traits::util::elaborate_predicates_with_span;
4 use rustc_infer::traits::{Obligation, ObligationCause, TraitObligation};
5 use rustc_middle::ty;
6 use rustc_span::{Span, DUMMY_SP};
7
8 use crate::traits::ObligationCtxt;
9
10 pub enum Ambiguity {
11     DefId(DefId),
12     ParamEnv(Span),
13 }
14
15 pub fn recompute_applicable_impls<'tcx>(
16     infcx: &InferCtxt<'tcx>,
17     obligation: &TraitObligation<'tcx>,
18 ) -> Vec<Ambiguity> {
19     let tcx = infcx.tcx;
20     let param_env = obligation.param_env;
21
22     let impl_may_apply = |impl_def_id| {
23         let ocx = ObligationCtxt::new_in_snapshot(infcx);
24         let placeholder_obligation =
25             infcx.instantiate_binder_with_placeholders(obligation.predicate);
26         let obligation_trait_ref =
27             ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref);
28
29         let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
30         let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst(tcx, impl_substs);
31         let impl_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref);
32
33         if let Err(_) =
34             ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, impl_trait_ref)
35         {
36             return false;
37         }
38
39         let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs);
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.instantiate_binder_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.instantiate_binder_with_fresh_vars(
55             DUMMY_SP,
56             LateBoundRegionConversionTime::HigherRankedType,
57             poly_trait_predicate,
58         );
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         }
67
68         ocx.select_where_possible().is_empty()
69     };
70
71     let mut ambiguities = Vec::new();
72
73     tcx.for_each_relevant_impl(
74         obligation.predicate.def_id(),
75         obligation.predicate.skip_binder().trait_ref.self_ty(),
76         |impl_def_id| {
77             if infcx.probe(|_| impl_may_apply(impl_def_id)) {
78                 ambiguities.push(Ambiguity::DefId(impl_def_id))
79             }
80         },
81     );
82
83     let predicates =
84         tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx);
85     for obligation in elaborate_predicates_with_span(tcx, predicates.into_iter()) {
86         let kind = obligation.predicate.kind();
87         if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder()
88             && param_env_candidate_may_apply(kind.rebind(trait_pred))
89         {
90             if kind.rebind(trait_pred.trait_ref) == ty::TraitRef::identity(tcx, trait_pred.def_id()) {
91                 ambiguities.push(Ambiguity::ParamEnv(tcx.def_span(trait_pred.def_id())))
92             } else {
93                 ambiguities.push(Ambiguity::ParamEnv(obligation.cause.span))
94             }
95         }
96     }
97
98     ambiguities
99 }