diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 7b2ff6d4b7db..20a29465bbd2 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -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; 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) { - 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); diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 6baf4e6c0489..ff5d80c8a16a 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -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); } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index bb0db874b675..38e70ec389e9 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -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, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 2662d6ef1908..ec8285c33de7 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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 + * + * 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`, 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. diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index c0686e1c8fcc..52e6bcf5b6d9 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -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 HigherRankedFoldable for ty::Binder { fn fold_contents<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder { ty::bind(self.value.fold_with(folder)) } } + +impl HigherRankedFoldable for Rc { + fn fold_contents<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Rc { + Rc::new((**self).fold_contents(folder)) + } +} + +/////////////////////////////////////////////////////////////////////////// // Some sample folders pub struct BottomUpFolder<'a, 'tcx: 'a> { diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 90238f791355..686774926496 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -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, + associated_type: Option) + -> Rc + 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, - associated_type: Option, - 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, + associated_type: Option, + 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, diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 3f90f5924739..55ed6720dba6 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -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> = 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 = diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index f0d480c719a9..0f9554cd417f 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -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 { - // 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; + // this must be overridden to do correctly, so as to account for higher-ranked + // behavior } #[deriving(Clone)] diff --git a/src/librustc/middle/typeck/infer/equate.rs b/src/librustc/middle/typeck/infer/equate.rs index 97453dc86efd..3874f5fc5e4a 100644 --- a/src/librustc/middle/typeck/infer/equate.rs +++ b/src/librustc/middle/typeck/infer/equate.rs @@ -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 { + try!(self.sub().trait_refs(a, b)); + self.sub().trait_refs(b, a) + } } diff --git a/src/librustc/middle/typeck/infer/lattice.rs b/src/librustc/middle/typeck/infer/lattice.rs index 5dbcaadf0df6..f7e6cef99af9 100644 --- a/src/librustc/middle/typeck/infer/lattice.rs +++ b/src/librustc/middle/typeck/infer/lattice.rs @@ -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) - -> Vec { - 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 - } -} diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs index 492ac5e92d3c..8856f42d1f5a 100644 --- a/src/librustc/middle/typeck/infer/lub.rs +++ b/src/librustc/middle/typeck/infer/lub.rs @@ -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 { - 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 { 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 { @@ -120,4 +120,8 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> { fn tys(&self, a: ty::t, b: ty::t) -> cres { super_lattice_tys(self, a, b) } + + fn trait_refs(&self, a: &ty::TraitRef, b: &ty::TraitRef) -> cres { + self.higher_ranked_lub(a, b) + } } diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 6f75192e6019..b4689ae098c9 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -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) -> String { + let t = self.resolve_type_vars_in_trait_ref_if_possible(&**t); trait_ref_to_string(self.tcx, &t) } diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index f3df33f7b0e6..f85cb85ff21a 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -63,16 +63,16 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { fn regions(&self, a: ty::Region, b: ty::Region) -> cres { 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 { 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 { 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 { self.higher_ranked_sub(a, b) } + + fn trait_refs(&self, a: &ty::TraitRef, b: &ty::TraitRef) -> cres { + self.higher_ranked_sub(a, b) + } } diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs index 745c76eb77f5..2f72d3cf50db 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc/middle/typeck/rscope.rs @@ -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 + { + self.base_scope.default_region_bound(span) + .map(|r| ty_fold::shift_region(r, 1)) + } + + fn anon_regions(&self, + span: Span, + count: uint) + -> Result, Option>> + { + 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) + } + } + } +} diff --git a/src/librustc_trans/driver/driver.rs b/src/librustc_trans/driver/driver.rs index ca70a37bf3d2..a0e2bf07b830 100644 --- a/src/librustc_trans/driver/driver.rs +++ b/src/librustc_trans/driver/driver.rs @@ -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));