|
10 | 10 |
|
11 | 11 | //! See `doc.rs` for high-level documentation
|
12 | 12 |
|
| 13 | +use super::Normalized; |
13 | 14 | use super::SelectionContext;
|
14 |
| -use super::{Obligation, ObligationCause}; |
| 15 | +use super::{ObligationCause}; |
| 16 | +use super::PredicateObligation; |
15 | 17 | use super::project;
|
16 | 18 | use super::util;
|
17 | 19 |
|
18 | 20 | use middle::subst::{Subst, TypeSpace};
|
19 |
| -use middle::ty::{self, Ty}; |
20 |
| -use middle::infer::InferCtxt; |
| 21 | +use middle::ty::{self, ToPolyTraitRef, Ty}; |
| 22 | +use middle::infer::{self, InferCtxt}; |
21 | 23 | use std::collections::HashSet;
|
22 | 24 | use std::rc::Rc;
|
23 | 25 | use syntax::ast;
|
24 | 26 | use syntax::codemap::DUMMY_SP;
|
25 | 27 | use util::ppaux::Repr;
|
26 | 28 |
|
27 |
| -pub fn impl_can_satisfy(infcx: &InferCtxt, |
28 |
| - impl1_def_id: ast::DefId, |
29 |
| - impl2_def_id: ast::DefId) |
30 |
| - -> bool |
| 29 | +/// True if there exist types that satisfy both of the two given impls. |
| 30 | +pub fn overlapping_impls(infcx: &InferCtxt, |
| 31 | + impl1_def_id: ast::DefId, |
| 32 | + impl2_def_id: ast::DefId) |
| 33 | + -> bool |
31 | 34 | {
|
32 | 35 | debug!("impl_can_satisfy(\
|
33 | 36 | impl1_def_id={}, \
|
34 | 37 | impl2_def_id={})",
|
35 | 38 | impl1_def_id.repr(infcx.tcx),
|
36 | 39 | impl2_def_id.repr(infcx.tcx));
|
37 | 40 |
|
38 |
| - let param_env = ty::empty_parameter_environment(infcx.tcx); |
39 |
| - let mut selcx = SelectionContext::intercrate(infcx, ¶m_env); |
40 |
| - let cause = ObligationCause::dummy(); |
41 |
| - |
42 |
| - // `impl1` provides an implementation of `Foo<X,Y> for Z`. |
43 |
| - let impl1_substs = |
44 |
| - util::fresh_substs_for_impl(infcx, DUMMY_SP, impl1_def_id); |
45 |
| - let impl1_trait_ref = |
46 |
| - (*ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap()).subst(infcx.tcx, &impl1_substs); |
47 |
| - let impl1_trait_ref = |
48 |
| - project::normalize(&mut selcx, cause.clone(), &impl1_trait_ref); |
49 |
| - |
50 |
| - // Determine whether `impl2` can provide an implementation for those |
51 |
| - // same types. |
52 |
| - let obligation = Obligation::new(cause, |
53 |
| - ty::Binder(ty::TraitPredicate { |
54 |
| - trait_ref: Rc::new(impl1_trait_ref.value), |
55 |
| - })); |
56 |
| - debug!("impl_can_satisfy(obligation={})", obligation.repr(infcx.tcx)); |
57 |
| - selcx.evaluate_impl(impl2_def_id, &obligation) && |
58 |
| - impl1_trait_ref.obligations.iter().all( |
59 |
| - |o| selcx.evaluate_obligation(o)) |
| 41 | + let param_env = &ty::empty_parameter_environment(infcx.tcx); |
| 42 | + let selcx = &mut SelectionContext::intercrate(infcx, param_env); |
| 43 | + infcx.probe(|_| { |
| 44 | + overlap(selcx, impl1_def_id, impl2_def_id) || overlap(selcx, impl2_def_id, impl1_def_id) |
| 45 | + }) |
| 46 | +} |
| 47 | + |
| 48 | +/// Can the types from impl `a` be used to satisfy impl `b`? |
| 49 | +/// (Including all conditions) |
| 50 | +fn overlap(selcx: &mut SelectionContext, |
| 51 | + a_def_id: ast::DefId, |
| 52 | + b_def_id: ast::DefId) |
| 53 | + -> bool |
| 54 | +{ |
| 55 | + let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx, a_def_id); |
| 56 | + let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx, b_def_id); |
| 57 | + |
| 58 | + // Does `a <: b` hold? If not, no overlap. |
| 59 | + if let Err(_) = infer::mk_sub_poly_trait_refs(selcx.infcx(), |
| 60 | + true, |
| 61 | + infer::Misc(DUMMY_SP), |
| 62 | + a_trait_ref.to_poly_trait_ref(), |
| 63 | + b_trait_ref.to_poly_trait_ref()) { |
| 64 | + return false; |
| 65 | + } |
| 66 | + |
| 67 | + // Are any of the obligations unsatisfiable? If so, no overlap. |
| 68 | + a_obligations.iter() |
| 69 | + .chain(b_obligations.iter()) |
| 70 | + .all(|o| selcx.evaluate_obligation(o)) |
| 71 | +} |
| 72 | + |
| 73 | +/// Instantiate fresh variables for all bound parameters of the impl |
| 74 | +/// and return the impl trait ref with those variables substituted. |
| 75 | +fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, |
| 76 | + impl_def_id: ast::DefId) |
| 77 | + -> (Rc<ty::TraitRef<'tcx>>, |
| 78 | + Vec<PredicateObligation<'tcx>>) |
| 79 | +{ |
| 80 | + let impl_substs = |
| 81 | + &util::fresh_substs_for_impl(selcx.infcx(), DUMMY_SP, impl_def_id); |
| 82 | + let impl_trait_ref = |
| 83 | + ty::impl_trait_ref(selcx.tcx(), impl_def_id).unwrap(); |
| 84 | + let impl_trait_ref = |
| 85 | + impl_trait_ref.subst(selcx.tcx(), impl_substs); |
| 86 | + let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = |
| 87 | + project::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref); |
| 88 | + |
| 89 | + let predicates = ty::lookup_predicates(selcx.tcx(), impl_def_id); |
| 90 | + let predicates = predicates.instantiate(selcx.tcx(), impl_substs); |
| 91 | + let Normalized { value: predicates, obligations: normalization_obligations2 } = |
| 92 | + project::normalize(selcx, ObligationCause::dummy(), &predicates); |
| 93 | + let impl_obligations = |
| 94 | + util::predicates_for_generics(selcx.tcx(), ObligationCause::dummy(), 0, &predicates); |
| 95 | + |
| 96 | + let impl_obligations: Vec<_> = |
| 97 | + impl_obligations.into_iter() |
| 98 | + .chain(normalization_obligations1.into_iter()) |
| 99 | + .chain(normalization_obligations2.into_iter()) |
| 100 | + .collect(); |
| 101 | + |
| 102 | + (impl_trait_ref, impl_obligations) |
60 | 103 | }
|
61 | 104 |
|
62 | 105 | pub enum OrphanCheckErr<'tcx> {
|
|
0 commit comments