|
1 | 1 | 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; |
3 | 4 | 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}; |
5 | 7 |
|
6 | 8 | use crate::traits::ObligationCtxt; |
7 | 9 |
|
| 10 | +pub enum Ambiguity { |
| 11 | + DefId(DefId), |
| 12 | + ParamEnv(Span), |
| 13 | +} |
| 14 | + |
8 | 15 | pub fn recompute_applicable_impls<'tcx>( |
9 | 16 | infcx: &InferCtxt<'tcx>, |
10 | 17 | obligation: &TraitObligation<'tcx>, |
11 | | -) -> Vec<DefId> { |
| 18 | +) -> Vec<Ambiguity> { |
12 | 19 | let tcx = infcx.tcx; |
13 | 20 | let param_env = obligation.param_env; |
14 | | - let dummy_cause = ObligationCause::dummy(); |
| 21 | + |
15 | 22 | let impl_may_apply = |impl_def_id| { |
16 | 23 | let ocx = ObligationCtxt::new_in_snapshot(infcx); |
17 | 24 | let placeholder_obligation = |
18 | 25 | infcx.replace_bound_vars_with_placeholders(obligation.predicate); |
19 | 26 | 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); |
21 | 28 |
|
22 | 29 | let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); |
23 | 30 | let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap().subst(tcx, impl_substs); |
24 | 31 | let impl_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref); |
25 | 32 |
|
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 | + { |
27 | 36 | return false; |
28 | 37 | } |
29 | 38 |
|
30 | 39 | 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, |
36 | 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 | + } |
37 | 67 |
|
38 | 68 | ocx.select_where_possible().is_empty() |
39 | 69 | }; |
40 | 70 |
|
41 | | - let mut impls = Vec::new(); |
| 71 | + let mut ambiguities = Vec::new(); |
| 72 | + |
42 | 73 | tcx.for_each_relevant_impl( |
43 | 74 | obligation.predicate.def_id(), |
44 | 75 | obligation.predicate.skip_binder().trait_ref.self_ty(), |
45 | 76 | |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)) |
48 | 79 | } |
49 | 80 | }, |
50 | 81 | ); |
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 |
52 | 101 | } |
0 commit comments