1
Fork 0

Introduce ImplHeader

This commit introduces the idea of an "impl header", which consists of
everything outside the impl body: the Self type, the trait
reference (when applicable), and predicates from `where` clauses. This
type is usable with the type folding machinery, making it possible to
work with impl headers at a higher and more generic level.
This commit is contained in:
Aaron Turon 2016-02-26 10:51:10 -08:00
parent 40c85cd8ae
commit 9cc3bfcceb
6 changed files with 107 additions and 75 deletions

View file

@ -458,14 +458,13 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
}
pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a_is_expected: bool,
origin: TypeOrigin,
a: ty::TraitRef<'tcx>,
b: ty::TraitRef<'tcx>)
-> UnitResult<'tcx>
a_is_expected: bool,
origin: TypeOrigin,
a: ty::TraitRef<'tcx>,
b: ty::TraitRef<'tcx>)
-> UnitResult<'tcx>
{
debug!("mk_eq_trait_refs({:?} <: {:?})",
a, b);
debug!("mk_eq_trait_refs({:?} = {:?})", a, b);
cx.eq_trait_refs(a_is_expected, origin, a, b)
}
@ -476,11 +475,25 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
b: ty::PolyTraitRef<'tcx>)
-> UnitResult<'tcx>
{
debug!("mk_sub_poly_trait_refs({:?} <: {:?})",
a, b);
debug!("mk_sub_poly_trait_refs({:?} <: {:?})", a, b);
cx.sub_poly_trait_refs(a_is_expected, origin, a, b)
}
pub fn mk_eq_impl_headers<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a_is_expected: bool,
origin: TypeOrigin,
a: ty::ImplHeader<'tcx>,
b: ty::ImplHeader<'tcx>)
-> UnitResult<'tcx>
{
debug!("mk_eq_impl_header({:?} = {:?})", a, b);
match (a.trait_ref, b.trait_ref) {
(Some(a_ref), Some(b_ref)) => mk_eq_trait_refs(cx, a_is_expected, a_ref, b_ref),
(None, None) => mk_eqty(cx, a_is_expected, a.self_ty, b.self_ty),
_ => cx.tcx.sess.bug("mk_eq_impl_headers given mismatched impl kinds"),
}
}
fn expected_found<T>(a_is_expected: bool,
a: T,
b: T)

View file

@ -10,10 +10,8 @@
//! See `README.md` for high-level documentation
use super::Normalized;
use super::SelectionContext;
use super::ObligationCause;
use super::PredicateObligation;
use super::{Normalized, SelectionContext};
use super::{Obligation, ObligationCause, PredicateObligation};
use super::project;
use super::util;
@ -21,18 +19,19 @@ use middle::cstore::LOCAL_CRATE;
use middle::def_id::DefId;
use middle::subst::{Subst, Substs, TypeSpace};
use middle::ty::{self, Ty, TyCtxt};
use middle::ty::error::TypeError;
use middle::infer::{self, InferCtxt, TypeOrigin};
use syntax::codemap::{DUMMY_SP, Span};
#[derive(Copy, Clone)]
struct InferIsLocal(bool);
/// If there are types that satisfy both impls, returns a `TraitRef`
/// If there are types that satisfy both impls, returns an `ImplTy`
/// with those types substituted (by updating the given `infcx`)
pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx>,
impl1_def_id: DefId,
impl2_def_id: DefId)
-> Option<ty::TraitRef<'tcx>>
-> Option<ImplTy<'tcx>>
{
debug!("impl_can_satisfy(\
impl1_def_id={:?}, \
@ -45,34 +44,28 @@ pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx>,
}
/// Can both impl `a` and impl `b` be satisfied by a common type (including
/// `where` clauses)? If so, returns a `TraitRef` that unifies the two impls.
/// `where` clauses)? If so, returns an `ImplHeader` that unifies the two impls.
fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>,
a_def_id: DefId,
b_def_id: DefId)
-> Option<ty::TraitRef<'tcx>>
-> Option<ImplHeader<'tcx>>
{
debug!("overlap(a_def_id={:?}, b_def_id={:?})",
a_def_id,
b_def_id);
let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx,
a_def_id,
util::fresh_type_vars_for_impl);
let a_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, a_def_id);
let b_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, b_def_id);
let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx,
b_def_id,
util::fresh_type_vars_for_impl);
debug!("overlap: a_trait_ref={:?} a_obligations={:?}", a_trait_ref, a_obligations);
debug!("overlap: b_trait_ref={:?} b_obligations={:?}", b_trait_ref, b_obligations);
debug!("overlap: a_impl_header={:?}", a_impl_header);
debug!("overlap: b_impl_header={:?}", b_impl_header);
// Do `a` and `b` unify? If not, no overlap.
if let Err(_) = infer::mk_eq_trait_refs(selcx.infcx(),
true,
TypeOrigin::Misc(DUMMY_SP),
a_trait_ref,
b_trait_ref) {
if let Err(_) = infer::mk_eq_impl_headers(selcx.infcx(),
true,
TypeOrigin::Misc(DUMMY_SP),
a_impl_header,
b_impl_header) {
return None;
}
@ -81,9 +74,13 @@ fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>,
// Are any of the obligations unsatisfiable? If so, no overlap.
let infcx = selcx.infcx();
let opt_failing_obligation =
a_obligations.iter()
.chain(&b_obligations)
.map(|o| infcx.resolve_type_vars_if_possible(o))
a_impl_header.prediates
.iter()
.chain(&b_impl_header.predicates)
.map(|p| infcx.resolve_type_vars_if_possible(p))
.map(|p| Obligation { cause: ObligationCause::dummy(),
recursion_depth: 0,
predicate: p })
.find(|o| !selcx.evaluate_obligation(o));
if let Some(failing_obligation) = opt_failing_obligation {
@ -91,7 +88,7 @@ fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>,
return None
}
Some(selcx.infcx().resolve_type_vars_if_possible(&a_trait_ref))
Some(selcx.infcx().resolve_type_vars_if_possible(&a_impl_header))
}
pub fn trait_ref_is_knowable<'tcx>(tcx: &TyCtxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> bool
@ -125,44 +122,6 @@ pub fn trait_ref_is_knowable<'tcx>(tcx: &TyCtxt<'tcx>, trait_ref: &ty::TraitRef<
orphan_check_trait_ref(tcx, trait_ref, InferIsLocal(true)).is_err()
}
type SubstsFn = for<'a,'tcx> fn(infcx: &InferCtxt<'a, 'tcx>,
span: Span,
impl_def_id: DefId)
-> Substs<'tcx>;
/// Instantiate fresh variables for all bound parameters of the impl
/// and return the impl trait ref with those variables substituted.
fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
impl_def_id: DefId,
substs_fn: SubstsFn)
-> (ty::TraitRef<'tcx>,
Vec<PredicateObligation<'tcx>>)
{
let impl_substs =
&substs_fn(selcx.infcx(), DUMMY_SP, impl_def_id);
let impl_trait_ref =
selcx.tcx().impl_trait_ref(impl_def_id).unwrap();
let impl_trait_ref =
impl_trait_ref.subst(selcx.tcx(), impl_substs);
let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } =
project::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref);
let predicates = selcx.tcx().lookup_predicates(impl_def_id);
let predicates = predicates.instantiate(selcx.tcx(), impl_substs);
let Normalized { value: predicates, obligations: normalization_obligations2 } =
project::normalize(selcx, ObligationCause::dummy(), &predicates);
let impl_obligations =
util::predicates_for_generics(ObligationCause::dummy(), 0, &predicates);
let impl_obligations: Vec<_> =
impl_obligations.into_iter()
.chain(normalization_obligations1)
.chain(normalization_obligations2)
.collect();
(impl_trait_ref, impl_obligations)
}
pub enum OrphanCheckErr<'tcx> {
NoLocalInputType,
UncoveredTy(Ty<'tcx>),

View file

@ -391,7 +391,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// The result is "true" if the obligation *may* hold and "false" if
// we can be sure it does not.
/// Evaluates whether the obligation `obligation` can be satisfied (by any means).
pub fn evaluate_obligation(&mut self,
obligation: &PredicateObligation<'tcx>)

View file

@ -146,6 +146,10 @@ pub trait TypeFolder<'tcx> : Sized {
t.super_fold_with(self)
}
fn fold_impl_header(&mut self, imp: &ty::ImplHeader<'tcx>) -> ty::ImplHeader<'tcx> {
imp.super_fold_with(self)
}
fn fold_substs(&mut self,
substs: &subst::Substs<'tcx>)
-> subst::Substs<'tcx> {

View file

@ -152,6 +152,41 @@ impl ImplOrTraitItemContainer {
}
}
/// The "header" of an impl is everything outside the body: a Self type, a trait
/// ref (in the case of a trait impl), and a set of predicates (from the
/// bounds/where clauses).
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct ImplHeader<'tcx> {
pub impl_def_id: DefId,
pub self_ty: Ty<'tcx>,
pub trait_ref: Option<TraitRef<'tcx>>,
pub predicates: Vec<Predicate<'tcx>>,
}
impl<'tcx> ImplHeader<'tcx> {
pub fn with_fresh_ty_vars<'a,'tcx>(selcx: &mut traits::SelectionContext<'a,'tcx>,
impl_def_id: DefId)
-> ImplHeader<'tcx>
{
let tcx = selcx.tcx();
let impl_generics = tcx.lookup_item_type(impl_def_id).generics;
let impl_substs = selcx.infcx().fresh_substs_for_generics(DUMMY_SP, &impl_generics);
let header = ImplHeader {
impl_def_id: impl_def_id,
self_ty: tcx.lookup_item_type(impl_def_id),
trait_ref: tcx.impl_trait_ref(impl_def_id),
predicates: tcx.lookup_predicates(impl_def_id),
}.subst(tcx, impl_substs);
let Normalized { value: mut header, obligations: obligations } =
proect::normalize(selcx, ObligationCause::dummy(), &header);
header.predicates.extend(obligations.into_iter().map(|o| o.predicate));
header
}
}
#[derive(Clone)]
pub enum ImplOrTraitItem<'tcx> {
ConstTraitItem(Rc<AssociatedConst<'tcx>>),

View file

@ -446,6 +446,28 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> {
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::ImplHeader<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
ty::ImplHeader {
impl_def_id: self.impl_def_id,
self_ty: self.self_ty.fold_with(folder),
trait_ref: self.trait_ref.map(|t| t.fold_with(folder)),
predicates: self.predicates.into_iter().map(|p| p.fold_with(folder)).collect(),
polarity: self.polarity,
}
}
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
folder.fold_impl_header(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.self_ty.visit_with(visitor) ||
self.trait_ref.map(|r| r.visit_with(visitor)).unwrap_or(false) ||
self.predicates.iter().any(|p| p.visit_with(visitor))
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::Region {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> Self {
*self