|
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