Introduce machinery for higher-ranked TraitRefs
This commit is contained in:
parent
ecdb741df7
commit
6fb68f1c81
@ -21,11 +21,13 @@ pub use self::DefRegion::*;
|
||||
use self::ScopeChain::*;
|
||||
|
||||
use session::Session;
|
||||
use middle::def;
|
||||
use middle::resolve::DefMap;
|
||||
use middle::subst;
|
||||
use middle::ty;
|
||||
use std::fmt;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::owned_slice::OwnedSlice;
|
||||
use syntax::parse::token::special_idents;
|
||||
use syntax::parse::token;
|
||||
use syntax::print::pprust::{lifetime_to_string};
|
||||
@ -52,7 +54,8 @@ pub type NamedRegionMap = NodeMap<DefRegion>;
|
||||
struct LifetimeContext<'a> {
|
||||
sess: &'a Session,
|
||||
named_region_map: &'a mut NamedRegionMap,
|
||||
scope: Scope<'a>
|
||||
scope: Scope<'a>,
|
||||
def_map: &'a DefMap,
|
||||
}
|
||||
|
||||
enum ScopeChain<'a> {
|
||||
@ -72,12 +75,13 @@ type Scope<'a> = &'a ScopeChain<'a>;
|
||||
|
||||
static ROOT_SCOPE: ScopeChain<'static> = RootScope;
|
||||
|
||||
pub fn krate(sess: &Session, krate: &ast::Crate) -> NamedRegionMap {
|
||||
pub fn krate(sess: &Session, krate: &ast::Crate, def_map: &DefMap) -> NamedRegionMap {
|
||||
let mut named_region_map = NodeMap::new();
|
||||
visit::walk_crate(&mut LifetimeContext {
|
||||
sess: sess,
|
||||
named_region_map: &mut named_region_map,
|
||||
scope: &ROOT_SCOPE
|
||||
scope: &ROOT_SCOPE,
|
||||
def_map: def_map,
|
||||
}, krate);
|
||||
sess.abort_if_errors();
|
||||
named_region_map
|
||||
@ -151,6 +155,27 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
|
||||
visit::walk_ty(this, ty);
|
||||
});
|
||||
}
|
||||
ast::TyPath(ref path, ref opt_bounds, id) => {
|
||||
// if this path references a trait, then this will resolve to
|
||||
// a trait ref, which introduces a binding scope.
|
||||
match self.def_map.borrow().get(&id) {
|
||||
Some(&def::DefTrait(..)) => {
|
||||
self.with(LateScope(&Vec::new(), self.scope), |this| {
|
||||
this.visit_path(path, id);
|
||||
});
|
||||
|
||||
match *opt_bounds {
|
||||
Some(ref bounds) => {
|
||||
visit::walk_ty_param_bounds_helper(self, bounds);
|
||||
}
|
||||
None => { }
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
visit::walk_ty(self, ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
visit::walk_ty(self, ty)
|
||||
}
|
||||
@ -177,7 +202,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
|
||||
|
||||
fn visit_generics(&mut self, generics: &ast::Generics) {
|
||||
for ty_param in generics.ty_params.iter() {
|
||||
self.visit_ty_param_bounds(&ty_param.bounds);
|
||||
visit::walk_ty_param_bounds_helper(self, &ty_param.bounds);
|
||||
match ty_param.default {
|
||||
Some(ref ty) => self.visit_ty(&**ty),
|
||||
None => {}
|
||||
@ -185,41 +210,14 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
|
||||
}
|
||||
for predicate in generics.where_clause.predicates.iter() {
|
||||
self.visit_ident(predicate.span, predicate.ident);
|
||||
self.visit_ty_param_bounds(&predicate.bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> LifetimeContext<'a> {
|
||||
fn with(&mut self, wrap_scope: ScopeChain, f: |&mut LifetimeContext|) {
|
||||
let LifetimeContext {sess, ref mut named_region_map, ..} = *self;
|
||||
let mut this = LifetimeContext {
|
||||
sess: sess,
|
||||
named_region_map: *named_region_map,
|
||||
scope: &wrap_scope
|
||||
};
|
||||
debug!("entering scope {}", this.scope);
|
||||
f(&mut this);
|
||||
debug!("exiting scope {}", this.scope);
|
||||
}
|
||||
|
||||
fn visit_ty_param_bounds(&mut self,
|
||||
bounds: &OwnedSlice<ast::TyParamBound>) {
|
||||
for bound in bounds.iter() {
|
||||
match *bound {
|
||||
ast::TraitTyParamBound(ref trait_ref) => {
|
||||
self.visit_poly_trait_ref(trait_ref);
|
||||
}
|
||||
ast::RegionTyParamBound(ref lifetime) => {
|
||||
self.visit_lifetime_ref(lifetime);
|
||||
}
|
||||
}
|
||||
visit::walk_ty_param_bounds_helper(self, &predicate.bounds);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_poly_trait_ref(&mut self, trait_ref: &ast::PolyTraitRef) {
|
||||
let ref_id = trait_ref.trait_ref.ref_id;
|
||||
self.with(LateScope(ref_id, &trait_ref.bound_lifetimes, self.scope), |this| {
|
||||
debug!("visit_poly_trait_ref trait_ref={}", trait_ref);
|
||||
|
||||
self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |this| {
|
||||
this.check_lifetime_defs(&trait_ref.bound_lifetimes);
|
||||
for lifetime in trait_ref.bound_lifetimes.iter() {
|
||||
this.visit_lifetime_decl(lifetime);
|
||||
|
@ -55,6 +55,7 @@ impl FulfillmentContext {
|
||||
obligation: Obligation)
|
||||
{
|
||||
debug!("register_obligation({})", obligation.repr(tcx));
|
||||
assert!(!obligation.trait_ref.has_escaping_regions());
|
||||
self.trait_obligations.push(obligation);
|
||||
}
|
||||
|
||||
|
@ -31,9 +31,7 @@ use middle::fast_reject;
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::subst::{Subst, Substs, VecPerParamSpace};
|
||||
use middle::ty;
|
||||
use middle::typeck::check::regionmanip;
|
||||
use middle::typeck::infer;
|
||||
use middle::typeck::infer::LateBoundRegionConversionTime::*;
|
||||
use middle::typeck::infer::{InferCtxt, TypeSkolemizer};
|
||||
use middle::ty_fold::TypeFoldable;
|
||||
use std::cell::RefCell;
|
||||
@ -211,6 +209,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
*/
|
||||
|
||||
debug!("select({})", obligation.repr(self.tcx()));
|
||||
assert!(!obligation.trait_ref.has_escaping_regions());
|
||||
|
||||
let stack = self.push_stack(None, obligation);
|
||||
match try!(self.candidate_from_obligation(&stack)) {
|
||||
@ -263,6 +262,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
debug!("evaluate_obligation({})",
|
||||
obligation.repr(self.tcx()));
|
||||
assert!(!obligation.trait_ref.has_escaping_regions());
|
||||
|
||||
let stack = self.push_stack(None, obligation);
|
||||
self.evaluate_stack(&stack).may_apply()
|
||||
@ -747,6 +747,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
debug!("candidate_from_obligation(cache_skol_trait_ref={}, obligation={})",
|
||||
cache_skol_trait_ref.repr(self.tcx()),
|
||||
stack.repr(self.tcx()));
|
||||
assert!(!stack.obligation.trait_ref.has_escaping_regions());
|
||||
|
||||
match self.check_candidate_cache(cache_skol_trait_ref.clone()) {
|
||||
Some(c) => {
|
||||
@ -1707,27 +1708,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
// FIXME(pcwalton): This is a bogus thing to do, but
|
||||
// it'll do for now until we get the new trait-bound
|
||||
// region skolemization working.
|
||||
let (_, new_signature) =
|
||||
regionmanip::replace_late_bound_regions(
|
||||
self.tcx(),
|
||||
closure_type.sig.binder_id,
|
||||
&closure_type.sig,
|
||||
|br| self.infcx.next_region_var(
|
||||
infer::LateBoundRegion(obligation.cause.span, br,
|
||||
infer::FnCall)));
|
||||
|
||||
let arguments_tuple = new_signature.inputs[0];
|
||||
let closure_sig = &closure_type.sig;
|
||||
let arguments_tuple = closure_sig.inputs[0];
|
||||
let substs =
|
||||
Substs::new_trait(
|
||||
vec![arguments_tuple.subst(self.tcx(), substs),
|
||||
closure_sig.output.unwrap().subst(self.tcx(), substs)],
|
||||
vec![],
|
||||
vec![],
|
||||
obligation.self_ty());
|
||||
let trait_ref = Rc::new(ty::TraitRef {
|
||||
def_id: obligation.trait_ref.def_id,
|
||||
substs: Substs::new_trait(
|
||||
vec![arguments_tuple.subst(self.tcx(), substs),
|
||||
new_signature.output.unwrap().subst(self.tcx(), substs)],
|
||||
vec![],
|
||||
vec![],
|
||||
obligation.self_ty())
|
||||
substs: substs,
|
||||
});
|
||||
|
||||
self.confirm(obligation.cause,
|
||||
|
@ -1105,6 +1105,23 @@ pub struct TyTrait {
|
||||
pub bounds: ExistentialBounds
|
||||
}
|
||||
|
||||
/**
|
||||
* A complete reference to a trait. These take numerous guises in syntax,
|
||||
* but perhaps the most recognizable form is in a where clause:
|
||||
*
|
||||
* T : Foo<U>
|
||||
*
|
||||
* This would be represented by a trait-reference where the def-id is the
|
||||
* def-id for the trait `Foo` and the substs defines `T` as parameter 0 in the
|
||||
* `SelfSpace` and `U` as parameter 0 in the `TypeSpace`.
|
||||
*
|
||||
* Trait references also appear in object types like `Foo<U>`, but in
|
||||
* that case the `Self` parameter is absent from the substitutions.
|
||||
*
|
||||
* Note that a `TraitRef` introduces a level of region binding, to
|
||||
* account for higher-ranked trait bounds like `T : for<'a> Foo<&'a
|
||||
* U>` or higher-ranked object types.
|
||||
*/
|
||||
#[deriving(Clone, PartialEq, Eq, Hash, Show)]
|
||||
pub struct TraitRef {
|
||||
pub def_id: DefId,
|
||||
@ -1410,6 +1427,14 @@ impl TraitRef {
|
||||
// associated types.
|
||||
self.substs.types.as_slice()
|
||||
}
|
||||
|
||||
pub fn has_escaping_regions(&self) -> bool {
|
||||
self.substs.has_regions_escaping_depth(1)
|
||||
}
|
||||
|
||||
pub fn has_bound_regions(&self) -> bool {
|
||||
self.substs.has_regions_escaping_depth(0)
|
||||
}
|
||||
}
|
||||
|
||||
/// When type checking, we use the `ParameterEnvironment` to track
|
||||
@ -1826,7 +1851,10 @@ impl FlagComputation {
|
||||
}
|
||||
|
||||
&ty_trait(box TyTrait { ref principal, ref bounds }) => {
|
||||
self.add_substs(&principal.substs);
|
||||
let mut computation = FlagComputation::new();
|
||||
computation.add_substs(&principal.substs);
|
||||
self.add_bound_computation(&computation);
|
||||
|
||||
self.add_bounds(bounds);
|
||||
}
|
||||
|
||||
@ -4708,9 +4736,99 @@ pub fn bounds_for_trait_ref(tcx: &ctxt,
|
||||
-> ty::ParamBounds
|
||||
{
|
||||
let trait_def = lookup_trait_def(tcx, trait_ref.def_id);
|
||||
|
||||
debug!("bounds_for_trait_ref(trait_def={}, trait_ref={})",
|
||||
trait_def.repr(tcx), trait_ref.repr(tcx));
|
||||
trait_def.bounds.subst(tcx, &trait_ref.substs)
|
||||
|
||||
// The interaction between HRTB and supertraits is not entirely
|
||||
// obvious. Let me walk you (and myself) through an example.
|
||||
//
|
||||
// Let's start with an easy case. Consider two traits:
|
||||
//
|
||||
// trait Foo<'a> : Bar<'a,'a> { }
|
||||
// trait Bar<'b,'c> { }
|
||||
//
|
||||
// Now, if we have a trait reference `for<'x> T : Foo<'x>`, then
|
||||
// we can deduce that `for<'x> T : Bar<'x,'x>`. Basically, if we
|
||||
// knew that `Foo<'x>` (for any 'x) then we also know that
|
||||
// `Bar<'x,'x>` (for any 'x). This more-or-less falls out from
|
||||
// normal substitution.
|
||||
//
|
||||
// In terms of why this is sound, the idea is that whenever there
|
||||
// is an impl of `T:Foo<'a>`, it must show that `T:Bar<'a,'a>`
|
||||
// holds. So if there is an impl of `T:Foo<'a>` that applies to
|
||||
// all `'a`, then we must know that `T:Bar<'a,'a>` holds for all
|
||||
// `'a`.
|
||||
//
|
||||
// Another example to be careful of is this:
|
||||
//
|
||||
// trait Foo1<'a> : for<'b> Bar1<'a,'b> { }
|
||||
// trait Bar1<'b,'c> { }
|
||||
//
|
||||
// Here, if we have `for<'x> T : Foo1<'x>`, then what do we know?
|
||||
// The answer is that we know `for<'x,'b> T : Bar1<'x,'b>`. The
|
||||
// reason is similar to the previous example: any impl of
|
||||
// `T:Foo1<'x>` must show that `for<'b> T : Bar1<'x, 'b>`. So
|
||||
// basically we would want to collapse the bound lifetimes from
|
||||
// the input (`trait_ref`) and the supertraits.
|
||||
//
|
||||
// To achieve this in practice is fairly straightforward. Let's
|
||||
// consider the more complicated scenario:
|
||||
//
|
||||
// - We start out with `for<'x> T : Foo1<'x>`. In this case, `'x`
|
||||
// has a De Bruijn index of 1. We want to produce `for<'x,'b> T : Bar1<'x,'b>`,
|
||||
// where both `'x` and `'b` would have a DB index of 1.
|
||||
// The substitution from the input trait-ref is therefore going to be
|
||||
// `'a => 'x` (where `'x` has a DB index of 1).
|
||||
// - The super-trait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an
|
||||
// early-bound parameter and `'b' is a late-bound parameter with a
|
||||
// DB index of 1.
|
||||
// - If we replace `'a` with `'x` from the input, it too will have
|
||||
// a DB index of 1, and thus we'll have `for<'x,'b> Bar1<'x,'b>`
|
||||
// just as we wanted.
|
||||
//
|
||||
// There is only one catch. If we just apply the substitution `'a
|
||||
// => 'x` to `for<'b> Bar1<'a,'b>`, the substitution code will
|
||||
// adjust the DB index because we substituting into a binder (it
|
||||
// tries to be so smart...) resulting in `for<'x> for<'b>
|
||||
// Bar1<'x,'b>` (we have no syntax for this, so use your
|
||||
// imagination). Basically the 'x will have DB index of 2 and 'b
|
||||
// will have DB index of 1. Not quite what we want. So we apply
|
||||
// the substitution to the *contents* of the trait reference,
|
||||
// rather than the trait reference itself (put another way, the
|
||||
// substitution code expects equal binding levels in the values
|
||||
// from the substitution and the value being substituted into, and
|
||||
// this trick achieves that).
|
||||
|
||||
// Carefully avoid the binder introduced by each trait-ref by
|
||||
// substituting over the substs, not the trait-refs themselves,
|
||||
// thus achieving the "collapse" described in the big comment
|
||||
// above.
|
||||
let trait_bounds: Vec<_> =
|
||||
trait_def.bounds.trait_bounds
|
||||
.iter()
|
||||
.map(|bound_trait_ref| {
|
||||
ty::TraitRef::new(bound_trait_ref.def_id,
|
||||
bound_trait_ref.substs.subst(tcx, &trait_ref.substs))
|
||||
})
|
||||
.map(|bound_trait_ref| Rc::new(bound_trait_ref))
|
||||
.collect();
|
||||
|
||||
debug!("bounds_for_trait_ref: trait_bounds={}",
|
||||
trait_bounds.repr(tcx));
|
||||
|
||||
// The region bounds and builtin bounds do not currently introduce
|
||||
// binders so we can just substitute in a straightforward way here.
|
||||
let region_bounds =
|
||||
trait_def.bounds.region_bounds.subst(tcx, &trait_ref.substs);
|
||||
let builtin_bounds =
|
||||
trait_def.bounds.builtin_bounds.subst(tcx, &trait_ref.substs);
|
||||
|
||||
ty::ParamBounds {
|
||||
trait_bounds: trait_bounds,
|
||||
region_bounds: region_bounds,
|
||||
builtin_bounds: builtin_bounds,
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate over attributes of a definition.
|
||||
|
@ -42,7 +42,6 @@ use middle::ty;
|
||||
use middle::traits;
|
||||
use middle::typeck;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::owned_slice::OwnedSlice;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
@ -477,6 +476,7 @@ impl TypeFoldable for traits::VtableParamData {
|
||||
// "super" routines: these are the default implementations for TypeFolder.
|
||||
//
|
||||
// They should invoke `foo.fold_with()` to do recursive folding.
|
||||
|
||||
pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
|
||||
t: ty::t)
|
||||
-> ty::t {
|
||||
@ -550,9 +550,21 @@ pub fn super_fold_closure_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
|
||||
abi: fty.abi,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn super_fold_trait_ref<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
|
||||
t: &ty::TraitRef)
|
||||
-> ty::TraitRef {
|
||||
-> ty::TraitRef
|
||||
{
|
||||
this.enter_region_binder();
|
||||
let result = super_fold_trait_ref_contents(this, t);
|
||||
this.exit_region_binder();
|
||||
result
|
||||
}
|
||||
|
||||
pub fn super_fold_trait_ref_contents<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
|
||||
t: &ty::TraitRef)
|
||||
-> ty::TraitRef
|
||||
{
|
||||
ty::TraitRef {
|
||||
def_id: t.def_id,
|
||||
substs: t.substs.fold_with(this),
|
||||
@ -691,11 +703,26 @@ impl HigherRankedFoldable for ty::FnSig {
|
||||
super_fold_fn_sig_contents(folder, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl HigherRankedFoldable for ty::TraitRef {
|
||||
fn fold_contents<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TraitRef {
|
||||
super_fold_trait_ref_contents(folder, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:TypeFoldable+Repr> HigherRankedFoldable for ty::Binder<T> {
|
||||
fn fold_contents<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder<T> {
|
||||
ty::bind(self.value.fold_with(folder))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:HigherRankedFoldable> HigherRankedFoldable for Rc<T> {
|
||||
fn fold_contents<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Rc<T> {
|
||||
Rc::new((**self).fold_contents(folder))
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Some sample folders
|
||||
|
||||
pub struct BottomUpFolder<'a, 'tcx: 'a> {
|
||||
|
@ -55,11 +55,10 @@ use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs};
|
||||
use middle::subst::{VecPerParamSpace};
|
||||
use middle::ty;
|
||||
use middle::typeck::lookup_def_tcx;
|
||||
use middle::typeck::infer;
|
||||
use middle::typeck::rscope::{UnelidableRscope, RegionScope, SpecificRscope, BindingRscope};
|
||||
use middle::typeck::rscope::{UnelidableRscope, RegionScope, SpecificRscope,
|
||||
ShiftedRscope, BindingRscope};
|
||||
use middle::typeck::rscope;
|
||||
use middle::typeck::TypeAndSubsts;
|
||||
use middle::typeck;
|
||||
use util::nodemap::DefIdMap;
|
||||
use util::ppaux::{Repr, UserString};
|
||||
|
||||
@ -414,6 +413,16 @@ fn convert_parenthesized_parameters<'tcx,AC>(this: &AC,
|
||||
vec![input_ty, output]
|
||||
}
|
||||
|
||||
pub fn instantiate_poly_trait_ref<'tcx,AC,RS>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
ast_trait_ref: &ast::PolyTraitRef,
|
||||
self_ty: Option<ty::t>,
|
||||
associated_type: Option<ty::t>)
|
||||
-> Rc<ty::TraitRef>
|
||||
where AC: AstConv<'tcx>, RS: RegionScope
|
||||
{
|
||||
instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty, associated_type)
|
||||
}
|
||||
|
||||
pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC,
|
||||
@ -434,16 +443,9 @@ pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC,
|
||||
match lookup_def_tcx(this.tcx(),
|
||||
ast_trait_ref.path.span,
|
||||
ast_trait_ref.ref_id) {
|
||||
def::DefTrait(trait_did) => {
|
||||
let trait_ref =
|
||||
Rc::new(ast_path_to_trait_ref(this,
|
||||
rscope,
|
||||
trait_did,
|
||||
self_ty,
|
||||
associated_type,
|
||||
&ast_trait_ref.path,
|
||||
ast_trait_ref.ref_id));
|
||||
|
||||
def::DefTrait(trait_def_id) => {
|
||||
let trait_ref = Rc::new(ast_path_to_trait_ref(this, rscope, trait_def_id, self_ty,
|
||||
associated_type, &ast_trait_ref.path));
|
||||
this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id,
|
||||
trait_ref.clone());
|
||||
trait_ref
|
||||
@ -456,28 +458,45 @@ pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC,
|
||||
rscope: &RS,
|
||||
trait_def_id: ast::DefId,
|
||||
self_ty: Option<ty::t>,
|
||||
associated_type: Option<ty::t>,
|
||||
path: &ast::Path,
|
||||
binder_id: ast::NodeId)
|
||||
-> ty::TraitRef
|
||||
where AC: AstConv<'tcx>,
|
||||
RS: RegionScope {
|
||||
fn ast_path_to_trait_ref<'tcx,AC,RS>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
trait_def_id: ast::DefId,
|
||||
self_ty: Option<ty::t>,
|
||||
associated_type: Option<ty::t>,
|
||||
path: &ast::Path)
|
||||
-> ty::TraitRef
|
||||
where AC: AstConv<'tcx>, RS: RegionScope
|
||||
{
|
||||
let trait_def = this.get_trait_def(trait_def_id);
|
||||
ty::TraitRef {
|
||||
def_id: trait_def_id,
|
||||
substs: ast_path_substs(this,
|
||||
rscope,
|
||||
trait_def_id,
|
||||
&trait_def.generics,
|
||||
self_ty,
|
||||
associated_type,
|
||||
path,
|
||||
binder_id)
|
||||
}
|
||||
|
||||
// the trait reference introduces a binding level here, so
|
||||
// we need to shift the `rscope`. It'd be nice if we could
|
||||
// do away with this rscope stuff and work this knowledge
|
||||
// into resolve_lifetimes, as we do with non-omitted
|
||||
// lifetimes. Oh well, not there yet.
|
||||
let shifted_rscope = ShiftedRscope::new(rscope);
|
||||
|
||||
let (regions, types) = match path.segments.last().unwrap().parameters {
|
||||
ast::AngleBracketedParameters(ref data) => {
|
||||
convert_angle_bracketed_parameters(this, &shifted_rscope, data)
|
||||
}
|
||||
ast::ParenthesizedParameters(ref data) => {
|
||||
(Vec::new(), convert_parenthesized_parameters(this, data))
|
||||
}
|
||||
};
|
||||
|
||||
let substs = create_substs_for_ast_path(this,
|
||||
&shifted_rscope,
|
||||
path.span,
|
||||
trait_def_id,
|
||||
&trait_def.generics,
|
||||
self_ty,
|
||||
types,
|
||||
regions,
|
||||
associated_type);
|
||||
|
||||
ty::TraitRef::new(trait_def_id, substs)
|
||||
}
|
||||
|
||||
pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
||||
@ -923,9 +942,9 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
||||
ast_ty.span,
|
||||
&[Rc::new(result.clone())],
|
||||
ast_bounds);
|
||||
ty::mk_trait(tcx,
|
||||
result,
|
||||
bounds)
|
||||
let result_ty = ty::mk_trait(tcx, result, bounds);
|
||||
debug!("ast_ty_to_ty: result_ty={}", result_ty.repr(this.tcx()));
|
||||
result_ty
|
||||
}
|
||||
def::DefTy(did, _) | def::DefStruct(did) => {
|
||||
ast_path_to_ty(this, rscope, did, path).ty
|
||||
@ -1562,7 +1581,7 @@ fn compute_region_bound<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
|
||||
|
||||
pub struct PartitionedBounds<'a> {
|
||||
pub builtin_bounds: ty::BuiltinBounds,
|
||||
pub trait_bounds: Vec<&'a ast::TraitRef>,
|
||||
pub trait_bounds: Vec<&'a ast::PolyTraitRef>,
|
||||
pub region_bounds: Vec<&'a ast::Lifetime>,
|
||||
}
|
||||
|
||||
@ -1584,8 +1603,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
|
||||
for &ast_bound in ast_bounds.iter() {
|
||||
match *ast_bound {
|
||||
ast::TraitTyParamBound(ref b) => {
|
||||
let b = &b.trait_ref; // FIXME
|
||||
match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
|
||||
match lookup_def_tcx(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) {
|
||||
def::DefTrait(trait_did) => {
|
||||
match trait_def_ids.get(&trait_did) {
|
||||
// Already seen this trait. We forbid
|
||||
@ -1593,10 +1611,10 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
|
||||
// reason).
|
||||
Some(span) => {
|
||||
span_err!(
|
||||
tcx.sess, b.path.span, E0127,
|
||||
tcx.sess, b.trait_ref.path.span, E0127,
|
||||
"trait `{}` already appears in the \
|
||||
list of bounds",
|
||||
b.path.user_string(tcx));
|
||||
b.trait_ref.path.user_string(tcx));
|
||||
tcx.sess.span_note(
|
||||
*span,
|
||||
"previous appearance is here");
|
||||
@ -1607,7 +1625,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
|
||||
None => { }
|
||||
}
|
||||
|
||||
trait_def_ids.insert(trait_did, b.path.span);
|
||||
trait_def_ids.insert(trait_did, b.trait_ref.path.span);
|
||||
|
||||
if ty::try_add_builtin_trait(tcx,
|
||||
trait_did,
|
||||
|
@ -2006,12 +2006,12 @@ fn conv_param_bounds<'tcx,AC>(this: &AC,
|
||||
astconv::partition_bounds(this.tcx(), span, all_bounds.as_slice());
|
||||
let trait_bounds: Vec<Rc<ty::TraitRef>> =
|
||||
trait_bounds.into_iter()
|
||||
.map(|b| {
|
||||
astconv::instantiate_trait_ref(this,
|
||||
&ExplicitRscope,
|
||||
b,
|
||||
Some(param_ty.to_ty(this.tcx())),
|
||||
Some(param_ty.to_ty(this.tcx())))
|
||||
.map(|bound| {
|
||||
astconv::instantiate_poly_trait_ref(this,
|
||||
&ExplicitRscope,
|
||||
bound,
|
||||
Some(param_ty.to_ty(this.tcx())),
|
||||
Some(param_ty.to_ty(this.tcx())))
|
||||
})
|
||||
.collect();
|
||||
let region_bounds: Vec<ty::Region> =
|
||||
|
@ -59,6 +59,7 @@ use syntax::codemap::Span;
|
||||
|
||||
pub trait Combine<'tcx> {
|
||||
fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx>;
|
||||
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.infcx().tcx }
|
||||
fn tag(&self) -> String;
|
||||
fn a_is_expected(&self) -> bool;
|
||||
fn trace(&self) -> TypeTrace;
|
||||
@ -296,26 +297,14 @@ pub trait Combine<'tcx> {
|
||||
Err(ty::terr_trait_stores_differ(vk, expected_found(self, a, b)))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn trait_refs(&self,
|
||||
a: &ty::TraitRef,
|
||||
b: &ty::TraitRef)
|
||||
-> cres<ty::TraitRef> {
|
||||
// Different traits cannot be related
|
||||
|
||||
// - NOTE in the future, expand out subtraits!
|
||||
|
||||
if a.def_id != b.def_id {
|
||||
Err(ty::terr_traits(
|
||||
expected_found(self, a.def_id, b.def_id)))
|
||||
} else {
|
||||
let substs = try!(self.substs(a.def_id, &a.substs, &b.substs));
|
||||
Ok(ty::TraitRef { def_id: a.def_id,
|
||||
substs: substs })
|
||||
}
|
||||
}
|
||||
-> cres<ty::TraitRef>;
|
||||
// this must be overridden to do correctly, so as to account for higher-ranked
|
||||
// behavior
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
|
@ -137,4 +137,9 @@ impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> {
|
||||
try!(self.sub().fn_sigs(a, b));
|
||||
self.sub().fn_sigs(b, a)
|
||||
}
|
||||
|
||||
fn trait_refs(&self, a: &ty::TraitRef, b: &ty::TraitRef) -> cres<ty::TraitRef> {
|
||||
try!(self.sub().trait_refs(a, b));
|
||||
self.sub().trait_refs(b, a)
|
||||
}
|
||||
}
|
||||
|
@ -31,13 +31,12 @@
|
||||
* a lattice.
|
||||
*/
|
||||
|
||||
use middle::ty::{RegionVid, TyVar};
|
||||
use middle::ty::{TyVar};
|
||||
use middle::ty;
|
||||
use middle::typeck::infer::*;
|
||||
use middle::typeck::infer::combine::*;
|
||||
use middle::typeck::infer::glb::Glb;
|
||||
use middle::typeck::infer::lub::Lub;
|
||||
use util::nodemap::FnvHashMap;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
pub trait LatticeDir {
|
||||
@ -101,27 +100,3 @@ pub fn super_lattice_tys<'tcx, L:LatticeDir+Combine<'tcx>>(this: &L,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Random utility functions used by LUB/GLB when computing LUB/GLB of
|
||||
// fn types
|
||||
|
||||
pub fn var_ids<'tcx, T: Combine<'tcx>>(this: &T,
|
||||
map: &FnvHashMap<ty::BoundRegion, ty::Region>)
|
||||
-> Vec<RegionVid> {
|
||||
map.iter().map(|(_, r)| match *r {
|
||||
ty::ReInfer(ty::ReVar(r)) => { r }
|
||||
r => {
|
||||
this.infcx().tcx.sess.span_bug(
|
||||
this.trace().origin.span(),
|
||||
format!("found non-region-vid: {}", r).as_slice());
|
||||
}
|
||||
}).collect()
|
||||
}
|
||||
|
||||
pub fn is_var_in_set(new_vars: &[RegionVid], r: ty::Region) -> bool {
|
||||
match r {
|
||||
ty::ReInfer(ty::ReVar(ref v)) => new_vars.iter().any(|x| x == v),
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> {
|
||||
fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields.clone()) }
|
||||
|
||||
fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
|
||||
let tcx = self.fields.infcx.tcx;
|
||||
let tcx = self.tcx();
|
||||
|
||||
debug!("{}.mts({}, {})",
|
||||
self.tag(),
|
||||
@ -107,10 +107,10 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> {
|
||||
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
|
||||
debug!("{}.regions({}, {})",
|
||||
self.tag(),
|
||||
a.repr(self.fields.infcx.tcx),
|
||||
b.repr(self.fields.infcx.tcx));
|
||||
a.repr(self.tcx()),
|
||||
b.repr(self.tcx()));
|
||||
|
||||
Ok(self.fields.infcx.region_vars.lub_regions(Subtype(self.trace()), a, b))
|
||||
Ok(self.infcx().region_vars.lub_regions(Subtype(self.trace()), a, b))
|
||||
}
|
||||
|
||||
fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
|
||||
@ -120,4 +120,8 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> {
|
||||
fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
|
||||
super_lattice_tys(self, a, b)
|
||||
}
|
||||
|
||||
fn trait_refs(&self, a: &ty::TraitRef, b: &ty::TraitRef) -> cres<ty::TraitRef> {
|
||||
self.higher_ranked_lub(a, b)
|
||||
}
|
||||
}
|
||||
|
@ -31,10 +31,9 @@ pub use self::skolemize::TypeSkolemizer;
|
||||
use middle::subst;
|
||||
use middle::subst::Substs;
|
||||
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid};
|
||||
use middle::ty::replace_late_bound_regions;
|
||||
use middle::ty;
|
||||
use middle::ty_fold;
|
||||
use middle::ty_fold::{TypeFolder, TypeFoldable};
|
||||
use middle::typeck::check::regionmanip::replace_late_bound_regions;
|
||||
use middle::ty_fold::{HigherRankedFoldable, TypeFolder, TypeFoldable};
|
||||
use std::cell::{RefCell};
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
@ -816,8 +815,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
format!("({})", tstrs.connect(", "))
|
||||
}
|
||||
|
||||
pub fn trait_ref_to_string(&self, t: &ty::TraitRef) -> String {
|
||||
let t = self.resolve_type_vars_in_trait_ref_if_possible(t);
|
||||
pub fn trait_ref_to_string(&self, t: &Rc<ty::TraitRef>) -> String {
|
||||
let t = self.resolve_type_vars_in_trait_ref_if_possible(&**t);
|
||||
trait_ref_to_string(self.tcx, &t)
|
||||
}
|
||||
|
||||
|
@ -63,16 +63,16 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
|
||||
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
|
||||
debug!("{}.regions({}, {})",
|
||||
self.tag(),
|
||||
a.repr(self.fields.infcx.tcx),
|
||||
b.repr(self.fields.infcx.tcx));
|
||||
self.fields.infcx.region_vars.make_subregion(Subtype(self.trace()), a, b);
|
||||
a.repr(self.tcx()),
|
||||
b.repr(self.tcx()));
|
||||
self.infcx().region_vars.make_subregion(Subtype(self.trace()), a, b);
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
|
||||
debug!("mts({} <: {})",
|
||||
a.repr(self.fields.infcx.tcx),
|
||||
b.repr(self.fields.infcx.tcx));
|
||||
a.repr(self.tcx()),
|
||||
b.repr(self.tcx()));
|
||||
|
||||
if a.mutbl != b.mutbl {
|
||||
return Err(ty::terr_mutability);
|
||||
@ -121,7 +121,7 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
|
||||
|
||||
fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
|
||||
debug!("{}.tys({}, {})", self.tag(),
|
||||
a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
|
||||
a.repr(self.tcx()), b.repr(self.tcx()));
|
||||
if a == b { return Ok(a); }
|
||||
|
||||
let infcx = self.fields.infcx;
|
||||
@ -158,5 +158,9 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
|
||||
fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
|
||||
self.higher_ranked_sub(a, b)
|
||||
}
|
||||
|
||||
fn trait_refs(&self, a: &ty::TraitRef, b: &ty::TraitRef) -> cres<ty::TraitRef> {
|
||||
self.higher_ranked_sub(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,9 +10,9 @@
|
||||
|
||||
|
||||
use middle::ty;
|
||||
use middle::ty_fold;
|
||||
|
||||
use std::cell::Cell;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
/// Defines strategies for handling regions that are omitted. For
|
||||
@ -136,3 +136,40 @@ impl RegionScope for BindingRscope {
|
||||
}
|
||||
}
|
||||
|
||||
/// A scope which simply shifts the Debruijn index of other scopes
|
||||
/// to account for binding levels.
|
||||
pub struct ShiftedRscope<'r> {
|
||||
base_scope: &'r RegionScope+'r
|
||||
}
|
||||
|
||||
impl<'r> ShiftedRscope<'r> {
|
||||
pub fn new(base_scope: &'r RegionScope+'r) -> ShiftedRscope<'r> {
|
||||
ShiftedRscope { base_scope: base_scope }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r> RegionScope for ShiftedRscope<'r> {
|
||||
fn default_region_bound(&self, span: Span) -> Option<ty::Region>
|
||||
{
|
||||
self.base_scope.default_region_bound(span)
|
||||
.map(|r| ty_fold::shift_region(r, 1))
|
||||
}
|
||||
|
||||
fn anon_regions(&self,
|
||||
span: Span,
|
||||
count: uint)
|
||||
-> Result<Vec<ty::Region>, Option<Vec<(String, uint)>>>
|
||||
{
|
||||
match self.base_scope.anon_regions(span, count) {
|
||||
Ok(mut v) => {
|
||||
for r in v.iter_mut() {
|
||||
*r = ty_fold::shift_region(*r, 1);
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
Err(errs) => {
|
||||
Err(errs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -385,7 +385,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
|
||||
syntax::ext::mtwt::clear_tables();
|
||||
|
||||
let named_region_map = time(time_passes, "lifetime resolution", (),
|
||||
|_| middle::resolve_lifetime::krate(&sess, krate));
|
||||
|_| middle::resolve_lifetime::krate(&sess, krate, &def_map));
|
||||
|
||||
time(time_passes, "looking for entry point", (),
|
||||
|_| middle::entry::find_entry_point(&sess, &ast_map));
|
||||
|
Loading…
x
Reference in New Issue
Block a user