diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs index 564d6a717ff93..c1fd83cab54cc 100644 --- a/src/librustc/front/std_inject.rs +++ b/src/librustc/front/std_inject.rs @@ -164,12 +164,12 @@ impl fold::Folder for PreludeInjector { segments: vec!( ast::PathSegment { identifier: token::str_to_ident("std"), - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, }, ast::PathSegment { identifier: token::str_to_ident("prelude"), - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, }), }; diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 703722ccb1cdb..d403efcf8cd26 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -369,7 +369,7 @@ fn path_node(ids: Vec ) -> ast::Path { global: false, segments: ids.move_iter().map(|identifier| ast::PathSegment { identifier: identifier, - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, }).collect() } @@ -381,7 +381,7 @@ fn path_node_global(ids: Vec ) -> ast::Path { global: true, segments: ids.move_iter().map(|identifier| ast::PathSegment { identifier: identifier, - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, }).collect() } diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index caf4670b40a9f..678e81b7fea7e 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -273,7 +273,7 @@ fn item_region_param_defs(item_doc: ebml::Doc, cdata: Cmd) tag_region_param_def_def_id); let def_id = reader::with_doc_data(def_id_doc, parse_def_id); let def_id = translate_def_id(cdata, def_id); - v.push(ty::RegionParameterDef { ident: ident.name, + v.push(ty::RegionParameterDef { name: ident.name, def_id: def_id }); true }); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 91c0d093653f7..b6eab7b8a7474 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -184,7 +184,7 @@ fn encode_region_param_defs(ebml_w: &mut writer::Encoder, ebml_w.start_tag(tag_region_param_def); ebml_w.start_tag(tag_region_param_def_ident); - encode_name(ebml_w, param.ident); + encode_name(ebml_w, param.name); ebml_w.end_tag(); ebml_w.wr_tagged_str(tag_region_param_def_def_id, diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index be3180596e02b..590487f20d09a 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -176,11 +176,11 @@ fn enc_region(w: &mut MemWriter, cx: @ctxt, r: ty::Region) { enc_bound_region(w, cx, br); mywrite!(w, "]"); } - ty::ReEarlyBound(node_id, index, ident) => { + ty::ReEarlyBound(node_id, index, name) => { mywrite!(w, "B[{}|{}|{}]", node_id, index, - token::get_name(ident)); + token::get_name(name)); } ty::ReFree(ref fr) => { mywrite!(w, "f[{}|", fr.scope_id); @@ -208,10 +208,10 @@ fn enc_bound_region(w: &mut MemWriter, cx: @ctxt, br: ty::BoundRegion) { ty::BrAnon(idx) => { mywrite!(w, "a{}|", idx); } - ty::BrNamed(d, s) => { + ty::BrNamed(d, name) => { mywrite!(w, "[{}|{}]", (cx.ds)(d), - token::get_name(s)); + token::get_name(name)); } ty::BrFresh(id) => { mywrite!(w, "f{}|", id); diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 0a0bcc4ae0e64..5cee3e1a20dd9 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -13,6 +13,7 @@ //! which are available for use externally when compiled as a library. use std::mem::replace; +use std::vec_ng::Vec; use metadata::csearch; use middle::lint; @@ -855,7 +856,7 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> { debug!("privacy - list {}", pid.node.id); let seg = ast::PathSegment { identifier: pid.node.name, - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, }; let segs = vec!(seg); diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index c8e28d45e3cf1..88eaf256be8cf 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -19,9 +19,11 @@ use driver::session; use std::cell::RefCell; +use std::vec_ng::Vec; use util::nodemap::NodeMap; use syntax::ast; use syntax::codemap::Span; +use syntax::opt_vec; use syntax::opt_vec::OptVec; use syntax::parse::token::special_idents; use syntax::parse::token; @@ -33,18 +35,31 @@ use syntax::visit::Visitor; // that it corresponds to pub type NamedRegionMap = NodeMap; +// Returns an instance of some type that implements std::fmt::Show +fn lifetime_show(lt_name: &ast::Name) -> token::InternedString { + token::get_name(*lt_name) +} + struct LifetimeContext { sess: session::Session, named_region_map: @RefCell, } enum ScopeChain<'a> { - ItemScope(&'a OptVec), - FnScope(ast::NodeId, &'a OptVec, &'a ScopeChain<'a>), - BlockScope(ast::NodeId, &'a ScopeChain<'a>), + /// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound + /// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc. + EarlyScope(uint, &'a Vec, Scope<'a>), + /// LateScope(binder_id, ['a, 'b, ...], s) extends s with late-bound + /// lifetimes introduced by the declaration binder_id. + LateScope(ast::NodeId, &'a Vec, Scope<'a>), + /// lifetimes introduced by items within a code block are scoped + /// to that block. + BlockScope(ast::NodeId, Scope<'a>), RootScope } +type Scope<'a> = &'a ScopeChain<'a>; + pub fn krate(sess: session::Session, krate: &ast::Crate) -> @RefCell { let mut ctxt = LifetimeContext { @@ -56,10 +71,11 @@ pub fn krate(sess: session::Session, krate: &ast::Crate) ctxt.named_region_map } -impl<'a> Visitor<&'a ScopeChain<'a>> for LifetimeContext { +impl<'a> Visitor> for LifetimeContext { fn visit_item(&mut self, item: &ast::Item, - _: &'a ScopeChain<'a>) { + _: Scope<'a>) { + let root = RootScope; let scope = match item.node { ast::ItemFn(..) | // fn lifetimes get added in visit_fn below ast::ItemMod(..) | @@ -74,7 +90,7 @@ impl<'a> Visitor<&'a ScopeChain<'a>> for LifetimeContext { ast::ItemImpl(ref generics, _, _, _) | ast::ItemTrait(ref generics, _, _) => { self.check_lifetime_names(&generics.lifetimes); - ItemScope(&generics.lifetimes) + EarlyScope(0, &generics.lifetimes, &root) } }; debug!("entering scope {:?}", scope); @@ -84,58 +100,50 @@ impl<'a> Visitor<&'a ScopeChain<'a>> for LifetimeContext { fn visit_fn(&mut self, fk: &visit::FnKind, fd: &ast::FnDecl, b: &ast::Block, s: Span, n: ast::NodeId, - scope: &'a ScopeChain<'a>) { + scope: Scope<'a>) { match *fk { visit::FkItemFn(_, generics, _, _) | visit::FkMethod(_, generics, _) => { - let scope1 = FnScope(n, &generics.lifetimes, scope); - self.check_lifetime_names(&generics.lifetimes); - debug!("pushing fn scope id={} due to item/method", n); - visit::walk_fn(self, fk, fd, b, s, n, &scope1); - debug!("popping fn scope id={} due to item/method", n); + self.visit_fn_decl( + n, generics, scope, + |this, scope1| visit::walk_fn(this, fk, fd, b, s, n, scope1)) } visit::FkFnBlock(..) => { - visit::walk_fn(self, fk, fd, b, s, n, scope); + visit::walk_fn(self, fk, fd, b, s, n, scope) } } } - fn visit_ty(&mut self, ty: &ast::Ty, - scope: &'a ScopeChain<'a>) { + fn visit_ty(&mut self, ty: &ast::Ty, scope: Scope<'a>) { match ty.node { - ast::TyClosure(closure) => { - let scope1 = FnScope(ty.id, &closure.lifetimes, scope); - self.check_lifetime_names(&closure.lifetimes); - debug!("pushing fn scope id={} due to type", ty.id); - visit::walk_ty(self, ty, &scope1); - debug!("popping fn scope id={} due to type", ty.id); - } - ast::TyBareFn(bare_fn) => { - let scope1 = FnScope(ty.id, &bare_fn.lifetimes, scope); - self.check_lifetime_names(&bare_fn.lifetimes); - debug!("pushing fn scope id={} due to type", ty.id); - visit::walk_ty(self, ty, &scope1); - debug!("popping fn scope id={} due to type", ty.id); - } - _ => { - visit::walk_ty(self, ty, scope); - } + ast::TyClosure(c) => push_fn_scope(self, ty, scope, &c.lifetimes), + ast::TyBareFn(c) => push_fn_scope(self, ty, scope, &c.lifetimes), + _ => visit::walk_ty(self, ty, scope), + } + + fn push_fn_scope(this: &mut LifetimeContext, + ty: &ast::Ty, + scope: Scope, + lifetimes: &Vec) { + let scope1 = LateScope(ty.id, lifetimes, scope); + this.check_lifetime_names(lifetimes); + debug!("pushing fn scope id={} due to type", ty.id); + visit::walk_ty(this, ty, &scope1); + debug!("popping fn scope id={} due to type", ty.id); } } fn visit_ty_method(&mut self, m: &ast::TypeMethod, - scope: &'a ScopeChain<'a>) { - let scope1 = FnScope(m.id, &m.generics.lifetimes, scope); - self.check_lifetime_names(&m.generics.lifetimes); - debug!("pushing fn scope id={} due to ty_method", m.id); - visit::walk_ty_method(self, m, &scope1); - debug!("popping fn scope id={} due to ty_method", m.id); + scope: Scope<'a>) { + self.visit_fn_decl( + m.id, &m.generics, scope, + |this, scope1| visit::walk_ty_method(this, m, scope1)) } fn visit_block(&mut self, b: &ast::Block, - scope: &'a ScopeChain<'a>) { + scope: Scope<'a>) { let scope1 = BlockScope(b.id, scope); debug!("pushing block scope {}", b.id); visit::walk_block(self, b, &scope1); @@ -144,8 +152,8 @@ impl<'a> Visitor<&'a ScopeChain<'a>> for LifetimeContext { fn visit_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime, - scope: &'a ScopeChain<'a>) { - if lifetime_ref.ident == special_idents::statik.name { + scope: Scope<'a>) { + if lifetime_ref.name == special_idents::statik.name { self.insert_lifetime(lifetime_ref, ast::DefStaticRegion); return; } @@ -153,10 +161,85 @@ impl<'a> Visitor<&'a ScopeChain<'a>> for LifetimeContext { } } +impl<'a> ScopeChain<'a> { + fn count_early_params(&self) -> uint { + /*! + * Counts the number of early-bound parameters that are in + * scope. Used when checking methods: the early-bound + * lifetime parameters declared on the method are assigned + * indices that come after the indices from the type. Given + * something like `impl<'a> Foo { ... fn bar<'b>(...) }` + * then `'a` gets index 0 and `'b` gets index 1. + */ + + match *self { + RootScope => 0, + EarlyScope(base, lifetimes, _) => base + lifetimes.len(), + LateScope(_, _, s) => s.count_early_params(), + BlockScope(_, _) => 0, + } + } +} + impl LifetimeContext { + /// Visits self by adding a scope and handling recursive walk over the contents with `walk`. + fn visit_fn_decl(&mut self, + n: ast::NodeId, + generics: &ast::Generics, + scope: Scope, + walk: |&mut LifetimeContext, Scope|) { + /*! + * Handles visiting fns and methods. These are a bit + * complicated because we must distinguish early- vs late-bound + * lifetime parameters. We do this by checking which lifetimes + * appear within type bounds; those are early bound lifetimes, + * and the rest are late bound. + * + * For example: + * + * fn foo<'a,'b,'c,T:Trait<'b>>(...) + * + * Here `'a` and `'c` are late bound but `'b` is early + * bound. Note that early- and late-bound lifetimes may be + * interspersed together. + * + * If early bound lifetimes are present, we separate them into + * their own list (and likewise for late bound). They will be + * numbered sequentially, starting from the lowest index that + * is already in scope (for a fn item, that will be 0, but for + * a method it might not be). Late bound lifetimes are + * resolved by name and associated with a binder id (`n`), so + * the ordering is not important there. + */ + + self.check_lifetime_names(&generics.lifetimes); + + let early_count = scope.count_early_params(); + let referenced_idents = free_lifetimes(&generics.ty_params); + debug!("pushing fn scope id={} due to fn item/method\ + referenced_idents={:?} \ + early_count={}", + n, + referenced_idents.map(lifetime_show), + early_count); + if referenced_idents.is_empty() { + let scope1 = LateScope(n, &generics.lifetimes, scope); + walk(self, &scope1) + } else { + let (early, late) = generics.lifetimes.clone().partition( + |l| referenced_idents.iter().any(|&i| i == l.name)); + + let scope1 = EarlyScope(early_count, &early, scope); + let scope2 = LateScope(n, &late, &scope1); + + walk(self, &scope2); + } + debug!("popping fn scope id={} due to fn item/method", n); + } + fn resolve_lifetime_ref(&self, lifetime_ref: &ast::Lifetime, - scope: &ScopeChain) { + scope: Scope) { // Walk up the scope chain, tracking the number of fn scopes // that we pass through, until we find a lifetime with the // given name or we run out of scopes. If we encounter a code @@ -175,23 +258,25 @@ impl LifetimeContext { break; } - ItemScope(lifetimes) => { + EarlyScope(base, lifetimes, s) => { match search_lifetimes(lifetimes, lifetime_ref) { - Some((index, decl_id)) => { + Some((offset, decl_id)) => { + let index = base + offset; let def = ast::DefEarlyBoundRegion(index, decl_id); self.insert_lifetime(lifetime_ref, def); return; } None => { - break; + depth += 1; + scope = s; } } } - FnScope(id, lifetimes, s) => { + LateScope(binder_id, lifetimes, s) => { match search_lifetimes(lifetimes, lifetime_ref) { Some((_index, decl_id)) => { - let def = ast::DefLateBoundRegion(id, depth, decl_id); + let def = ast::DefLateBoundRegion(binder_id, depth, decl_id); self.insert_lifetime(lifetime_ref, def); return; } @@ -211,7 +296,7 @@ impl LifetimeContext { fn resolve_free_lifetime_ref(&self, scope_id: ast::NodeId, lifetime_ref: &ast::Lifetime, - scope: &ScopeChain) { + scope: Scope) { // Walk up the scope chain, tracking the outermost free scope, // until we encounter a scope that contains the named lifetime // or we run out of scopes. @@ -229,12 +314,8 @@ impl LifetimeContext { break; } - ItemScope(lifetimes) => { - search_result = search_lifetimes(lifetimes, lifetime_ref); - break; - } - - FnScope(_, lifetimes, s) => { + EarlyScope(_, lifetimes, s) | + LateScope(_, lifetimes, s) => { search_result = search_lifetimes(lifetimes, lifetime_ref); if search_result.is_some() { break; @@ -262,32 +343,32 @@ impl LifetimeContext { self.sess.span_err( lifetime_ref.span, format!("use of undeclared lifetime name `'{}`", - token::get_name(lifetime_ref.ident))); + token::get_name(lifetime_ref.name))); } - fn check_lifetime_names(&self, lifetimes: &OptVec) { + fn check_lifetime_names(&self, lifetimes: &Vec) { for i in range(0, lifetimes.len()) { let lifetime_i = lifetimes.get(i); let special_idents = [special_idents::statik]; for lifetime in lifetimes.iter() { - if special_idents.iter().any(|&i| i.name == lifetime.ident) { + if special_idents.iter().any(|&i| i.name == lifetime.name) { self.sess.span_err( lifetime.span, format!("illegal lifetime parameter name: `{}`", - token::get_name(lifetime.ident))); + token::get_name(lifetime.name))); } } for j in range(i + 1, lifetimes.len()) { let lifetime_j = lifetimes.get(j); - if lifetime_i.ident == lifetime_j.ident { + if lifetime_i.name == lifetime_j.name { self.sess.span_err( lifetime_j.span, format!("lifetime name `'{}` declared twice in \ the same scope", - token::get_name(lifetime_j.ident))); + token::get_name(lifetime_j.name))); } } } @@ -311,13 +392,54 @@ impl LifetimeContext { } } -fn search_lifetimes(lifetimes: &OptVec, +fn search_lifetimes(lifetimes: &Vec, lifetime_ref: &ast::Lifetime) -> Option<(uint, ast::NodeId)> { for (i, lifetime_decl) in lifetimes.iter().enumerate() { - if lifetime_decl.ident == lifetime_ref.ident { + if lifetime_decl.name == lifetime_ref.name { return Some((i, lifetime_decl.id)); } } return None; } + +/////////////////////////////////////////////////////////////////////////// + +pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec { + let referenced_idents = free_lifetimes(&generics.ty_params); + if referenced_idents.is_empty() { + return Vec::new(); + } + + generics.lifetimes.iter() + .filter(|l| referenced_idents.iter().any(|&i| i == l.name)) + .map(|l| *l) + .collect() +} + +pub fn free_lifetimes(ty_params: &OptVec) -> OptVec { + /*! + * Gathers up and returns the names of any lifetimes that appear + * free in `ty_params`. Of course, right now, all lifetimes appear + * free, since we don't currently have any binders in type parameter + * declarations; just being forwards compatible with future extensions. + */ + + let mut collector = FreeLifetimeCollector { names: opt_vec::Empty }; + for ty_param in ty_params.iter() { + visit::walk_ty_param_bounds(&mut collector, &ty_param.bounds, ()); + } + return collector.names; + + struct FreeLifetimeCollector { + names: OptVec, + } + + impl Visitor<()> for FreeLifetimeCollector { + fn visit_lifetime_ref(&mut self, + lifetime_ref: &ast::Lifetime, + _: ()) { + self.names.push(lifetime_ref.name); + } + } +} diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 6c48440421f6f..b0cf17c5b5467 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -276,7 +276,7 @@ impl Subst for ty::Region { // bound in *fn types*. Region substitution of the bound // regions that appear in a function signature is done using // the specialized routine - // `middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig()`. + // `middle::typeck::check::regionmanip::replace_late_regions_in_fn_sig()`. match self { &ty::ReEarlyBound(_, i, _) => { match substs.regions { diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 0e7c371b43d7f..6ade20d29136d 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -540,7 +540,7 @@ pub fn create_function_debug_context(cx: &CrateContext, return FunctionWithoutDebugInfo; } - let empty_generics = ast::Generics { lifetimes: opt_vec::Empty, ty_params: opt_vec::Empty }; + let empty_generics = ast::Generics { lifetimes: Vec::new(), ty_params: opt_vec::Empty }; let fnitem = cx.tcx.map.get(fn_ast_id); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 4d0f6704379d5..b2a879b1946e1 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -996,7 +996,7 @@ pub struct TypeParameterDef { #[deriving(Encodable, Decodable, Clone)] pub struct RegionParameterDef { - ident: ast::Name, + name: ast::Name, def_id: ast::DefId, } @@ -1008,6 +1008,7 @@ pub struct Generics { type_param_defs: Rc >, /// List of region parameters declared on the item. + /// For a fn or method, only includes *early-bound* lifetimes. region_param_defs: Rc >, } @@ -5077,6 +5078,7 @@ pub fn construct_parameter_environment( item_type_params: &[TypeParameterDef], method_type_params: &[TypeParameterDef], item_region_params: &[RegionParameterDef], + method_region_params: &[RegionParameterDef], free_id: ast::NodeId) -> ParameterEnvironment { @@ -5104,11 +5106,24 @@ pub fn construct_parameter_environment( }); // map bound 'a => free 'a - let region_params = item_region_params.iter(). - map(|r| ty::ReFree(ty::FreeRegion { - scope_id: free_id, - bound_region: ty::BrNamed(r.def_id, r.ident)})). - collect(); + let region_params = { + fn push_region_params(accum: OptVec, + free_id: ast::NodeId, + region_params: &[RegionParameterDef]) + -> OptVec { + let mut accum = accum; + for r in region_params.iter() { + accum.push( + ty::ReFree(ty::FreeRegion { + scope_id: free_id, + bound_region: ty::BrNamed(r.def_id, r.name)})); + } + accum + } + + let t = push_region_params(opt_vec::Empty, free_id, item_region_params); + push_region_params(t, free_id, method_region_params) + }; let free_substs = substs { self_ty: self_ty, @@ -5130,6 +5145,15 @@ pub fn construct_parameter_environment( } }); + debug!("construct_parameter_environment: free_id={} \ + free_subst={} \ + self_param_bound={} \ + type_param_bound={}", + free_id, + free_substs.repr(tcx), + self_bound_substd.repr(tcx), + type_param_bounds_substd.repr(tcx)); + ty::ParameterEnvironment { free_substs: free_substs, self_param_bound: self_bound_substd, diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 40e836ac0d9ad..e8770f9d142cf 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -92,18 +92,18 @@ pub fn ast_region_to_region(tcx: ty::ctxt, lifetime: &ast::Lifetime) Some(&ast::DefLateBoundRegion(binder_id, _, id)) => { ty::ReLateBound(binder_id, ty::BrNamed(ast_util::local_def(id), - lifetime.ident)) + lifetime.name)) } Some(&ast::DefEarlyBoundRegion(index, id)) => { - ty::ReEarlyBound(id, index, lifetime.ident) + ty::ReEarlyBound(id, index, lifetime.name) } Some(&ast::DefFreeRegion(scope_id, id)) => { ty::ReFree(ty::FreeRegion { scope_id: scope_id, bound_region: ty::BrNamed(ast_util::local_def(id), - lifetime.ident) + lifetime.name) }) } }; @@ -186,9 +186,9 @@ fn ast_path_substs( } match anon_regions { - Ok(v) => opt_vec::from(v.move_iter().collect()), - Err(()) => opt_vec::from(Vec::from_fn(expected_num_region_params, - |_| ty::ReStatic)) // hokey + Ok(v) => v.move_iter().collect(), + Err(()) => Vec::from_fn(expected_num_region_params, + |_| ty::ReStatic) // hokey } }; @@ -231,7 +231,7 @@ fn ast_path_substs( .collect(); let mut substs = substs { - regions: ty::NonerasedRegions(regions), + regions: ty::NonerasedRegions(opt_vec::from(regions)), self_ty: self_ty, tps: tps }; diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 0cf0fa5897aa9..ca36fca687abd 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -93,7 +93,7 @@ use middle::typeck::MethodCallee; use middle::typeck::{MethodOrigin, MethodParam}; use middle::typeck::{MethodStatic, MethodObject}; use middle::typeck::{param_numbered, param_self, param_index}; -use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig; +use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; use util::common::indenter; use util::ppaux::Repr; @@ -428,7 +428,7 @@ impl<'a> LookupContext<'a> { substs: &ty::substs) { debug!("push_inherent_candidates_from_object(did={}, substs={})", self.did_to_str(did), - substs_to_str(self.tcx(), substs)); + substs.repr(self.tcx())); let _indenter = indenter(); // It is illegal to invoke a method on a trait instance that @@ -554,7 +554,8 @@ impl<'a> LookupContext<'a> { match mk_cand(bound_trait_ref, method, pos, this_bound_idx) { Some(cand) => { - debug!("pushing inherent candidate for param: {:?}", cand); + debug!("pushing inherent candidate for param: {}", + cand.repr(self.tcx())); self.inherent_candidates.borrow_mut().get().push(cand); } None => {} @@ -938,8 +939,9 @@ impl<'a> LookupContext<'a> { let mut j = i + 1; while j < candidates.len() { let candidate_b = &candidates[j]; - debug!("attempting to merge {:?} and {:?}", - candidate_a, candidate_b); + debug!("attempting to merge {} and {}", + candidate_a.repr(self.tcx()), + candidate_b.repr(self.tcx())); let candidates_same = match (&candidate_a.origin, &candidate_b.origin) { (&MethodParam(ref p1), &MethodParam(ref p2)) => { @@ -984,9 +986,10 @@ impl<'a> LookupContext<'a> { let tcx = self.tcx(); - debug!("confirm_candidate(expr={}, candidate={})", + debug!("confirm_candidate(expr={}, rcvr_ty={}, candidate={})", self.expr.repr(tcx), - self.cand_to_str(candidate)); + self.ty_to_str(rcvr_ty), + candidate.repr(self.tcx())); self.enforce_object_limitations(candidate); self.enforce_drop_trait_limitations(candidate); @@ -994,9 +997,9 @@ impl<'a> LookupContext<'a> { // static methods should never have gotten this far: assert!(candidate.method_ty.explicit_self != SelfStatic); - // Determine the values for the type parameters of the method. + // Determine the values for the generic parameters of the method. // If they were not explicitly supplied, just construct fresh - // type variables. + // variables. let num_supplied_tps = self.supplied_tps.len(); let num_method_tps = candidate.method_ty.generics.type_param_defs().len(); let m_substs = { @@ -1018,12 +1021,26 @@ impl<'a> LookupContext<'a> { } }; + // Determine values for the early-bound lifetime parameters. + // FIXME -- permit users to manually specify lifetimes + let mut all_regions = match candidate.rcvr_substs.regions { + NonerasedRegions(ref v) => v.clone(), + ErasedRegions => tcx.sess.span_bug(self.expr.span, "ErasedRegions") + }; + let m_regions = + self.fcx.infcx().region_vars_for_defs( + self.expr.span, + candidate.method_ty.generics.region_param_defs.borrow().as_slice()); + for &r in m_regions.iter() { + all_regions.push(r); + } + // Construct the full set of type parameters for the method, // which is equal to the class tps + the method tps. let all_substs = substs { tps: vec_ng::append(candidate.rcvr_substs.tps.clone(), m_substs.as_slice()), - regions: candidate.rcvr_substs.regions.clone(), + regions: NonerasedRegions(all_regions), self_ty: candidate.rcvr_substs.self_ty, }; @@ -1057,10 +1074,10 @@ impl<'a> LookupContext<'a> { // Replace any bound regions that appear in the function // signature with region variables - let (_, fn_sig) = replace_bound_regions_in_fn_sig( tcx, &fn_sig, |br| { - self.fcx.infcx().next_region_var( - infer::BoundRegionInFnCall(self.expr.span, br)) - }); + let (_, fn_sig) = replace_late_bound_regions_in_fn_sig( + tcx, &fn_sig, + |br| self.fcx.infcx().next_region_var( + infer::LateBoundRegion(self.expr.span, br))); let transformed_self_ty = *fn_sig.inputs.get(0); let fty = ty::mk_bare_fn(tcx, ty::BareFnTy { sig: fn_sig, @@ -1245,7 +1262,7 @@ impl<'a> LookupContext<'a> { // candidate method's `self_ty`. fn is_relevant(&self, rcvr_ty: ty::t, candidate: &Candidate) -> bool { debug!("is_relevant(rcvr_ty={}, candidate={})", - self.ty_to_str(rcvr_ty), self.cand_to_str(candidate)); + self.ty_to_str(rcvr_ty), candidate.repr(self.tcx())); return match candidate.method_ty.explicit_self { SelfStatic => { @@ -1385,13 +1402,6 @@ impl<'a> LookupContext<'a> { self.fcx.infcx().ty_to_str(t) } - fn cand_to_str(&self, cand: &Candidate) -> ~str { - format!("Candidate(rcvr_ty={}, rcvr_substs={}, origin={:?})", - cand.rcvr_match_condition.repr(self.tcx()), - ty::substs_to_str(self.tcx(), &cand.rcvr_substs), - cand.origin) - } - fn did_to_str(&self, did: DefId) -> ~str { ty::item_path_str(self.tcx(), did) } @@ -1401,6 +1411,15 @@ impl<'a> LookupContext<'a> { } } +impl Repr for Candidate { + fn repr(&self, tcx: ty::ctxt) -> ~str { + format!("Candidate(rcvr_ty={}, rcvr_substs={}, origin={:?})", + self.rcvr_match_condition.repr(tcx), + self.rcvr_substs.repr(tcx), + self.origin) + } +} + impl Repr for RcvrMatchCondition { fn repr(&self, tcx: ty::ctxt) -> ~str { match *self { diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 3c98f3defd6e6..026d2d5d73454 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -97,7 +97,7 @@ use middle::typeck::check::method::{AutoderefReceiver}; use middle::typeck::check::method::{AutoderefReceiverFlag}; use middle::typeck::check::method::{CheckTraitsAndInherentMethods}; use middle::typeck::check::method::{DontAutoderefReceiver}; -use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig; +use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; use middle::typeck::check::regionmanip::relate_free_regions; use middle::typeck::check::vtable::{LocationInfo, VtableContext}; use middle::typeck::CrateCtxt; @@ -439,7 +439,7 @@ fn check_fn(ccx: @CrateCtxt, // First, we have to replace any bound regions in the fn type with free ones. // The free region references will be bound the node_id of the body block. - let (_, fn_sig) = replace_bound_regions_in_fn_sig(tcx, fn_sig, |br| { + let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(tcx, fn_sig, |br| { ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br}) }); @@ -563,13 +563,13 @@ pub fn check_item(ccx: @CrateCtxt, it: &ast::Item) { ast::ItemFn(decl, _, _, _, body) => { let fn_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); - // FIXME(#5121) -- won't work for lifetimes that appear in type bounds let param_env = ty::construct_parameter_environment( ccx.tcx, None, fn_tpt.generics.type_param_defs(), [], [], + fn_tpt.generics.region_param_defs.borrow().as_slice(), body.id); check_bare_fn(ccx, decl, body, it.id, fn_tpt.ty, param_env); @@ -679,6 +679,7 @@ fn check_method_body(ccx: @CrateCtxt, item_generics.type_param_defs(), method_generics.type_param_defs(), item_generics.region_param_defs(), + method_generics.region_param_defs(), method.body.id); // Compute the fty from point of view of inside fn @@ -901,7 +902,7 @@ fn compare_impl_method(tcx: ty::ctxt, impl_generics.region_param_defs().iter(). map(|l| ty::ReFree(ty::FreeRegion { scope_id: impl_m_body_id, - bound_region: ty::BrNamed(l.def_id, l.ident)})). + bound_region: ty::BrNamed(l.def_id, l.name)})). collect(); let dummy_substs = ty::substs { tps: vec_ng::append(dummy_impl_tps, dummy_method_tps.as_slice()), @@ -1439,22 +1440,17 @@ pub fn impl_self_ty(vcx: &VtableContext, -> ty_param_substs_and_ty { let tcx = vcx.tcx(); - let (n_tps, n_rps, raw_ty) = { - let ity = ty::lookup_item_type(tcx, did); + let ity = ty::lookup_item_type(tcx, did); + let (n_tps, rps, raw_ty) = (ity.generics.type_param_defs().len(), - ity.generics.region_param_defs().len(), - ity.ty) - }; + ity.generics.region_param_defs(), + ity.ty); - let rps = - vcx.infcx.next_region_vars( - infer::BoundRegionInTypeOrImpl(location_info.span), - n_rps); + let rps = vcx.infcx.region_vars_for_defs(location_info.span, rps); let tps = vcx.infcx.next_ty_vars(n_tps); let substs = substs { - regions: ty::NonerasedRegions(opt_vec::from(rps.move_iter() - .collect())), + regions: ty::NonerasedRegions(rps), self_ty: None, tps: tps, }; @@ -1888,9 +1884,8 @@ fn check_expr_with_unifier(fcx: @FnCtxt, // Replace any bound regions that appear in the function // signature with region variables - let (_, fn_sig) = replace_bound_regions_in_fn_sig(fcx.tcx(), fn_sig, |br| { - fcx.infcx() - .next_region_var(infer::BoundRegionInFnCall(call_expr.span, br)) + let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(fcx.tcx(), fn_sig, |br| { + fcx.infcx().next_region_var(infer::LateBoundRegion(call_expr.span, br)) }); // Call the generic checker. @@ -2214,7 +2209,7 @@ fn check_expr_with_unifier(fcx: @FnCtxt, match expected_sty { Some(ty::ty_closure(ref cenv)) => { let (_, sig) = - replace_bound_regions_in_fn_sig( + replace_late_bound_regions_in_fn_sig( tcx, &cenv.sig, |_| fcx.inh.infcx.fresh_bound_region(expr.id)); (Some(sig), cenv.purity, cenv.sigil, @@ -2462,16 +2457,14 @@ fn check_expr_with_unifier(fcx: @FnCtxt, // determine whether the class is region-parameterized. let item_type = ty::lookup_item_type(tcx, class_id); let type_parameter_count = item_type.generics.type_param_defs().len(); - let region_parameter_count = item_type.generics.region_param_defs().len(); + let region_param_defs = item_type.generics.region_param_defs(); let raw_type = item_type.ty; // Generate the struct type. - let regions = fcx.infcx().next_region_vars( - infer::BoundRegionInTypeOrImpl(span), - region_parameter_count).move_iter().collect(); + let regions = fcx.infcx().region_vars_for_defs(span, region_param_defs); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); let substitutions = substs { - regions: ty::NonerasedRegions(opt_vec::from(regions)), + regions: ty::NonerasedRegions(regions), self_ty: None, tps: type_parameters }; @@ -2520,16 +2513,14 @@ fn check_expr_with_unifier(fcx: @FnCtxt, // determine whether the enum is region-parameterized. let item_type = ty::lookup_item_type(tcx, enum_id); let type_parameter_count = item_type.generics.type_param_defs().len(); - let region_parameter_count = item_type.generics.region_param_defs().len(); + let region_param_defs = item_type.generics.region_param_defs(); let raw_type = item_type.ty; // Generate the enum type. - let regions = fcx.infcx().next_region_vars( - infer::BoundRegionInTypeOrImpl(span), - region_parameter_count).move_iter().collect(); + let regions = fcx.infcx().region_vars_for_defs(span, region_param_defs); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); let substitutions = substs { - regions: ty::NonerasedRegions(opt_vec::from(regions)), + regions: ty::NonerasedRegions(regions), self_ty: None, tps: type_parameters }; @@ -3727,8 +3718,8 @@ pub fn instantiate_path(fcx: @FnCtxt, let num_expected_regions = tpt.generics.region_param_defs().len(); let num_supplied_regions = pth.segments.last().unwrap().lifetimes.len(); let regions = if num_expected_regions == num_supplied_regions { - pth.segments.last().unwrap().lifetimes.map( - |l| ast_region_to_region(fcx.tcx(), l)) + opt_vec::from(pth.segments.last().unwrap().lifetimes.map( + |l| ast_region_to_region(fcx.tcx(), l))) } else { if num_supplied_regions != 0 { fcx.ccx.tcx.sess.span_err( @@ -3741,9 +3732,7 @@ pub fn instantiate_path(fcx: @FnCtxt, nsupplied = num_supplied_regions)); } - opt_vec::from(fcx.infcx().next_region_vars( - infer::BoundRegionInTypeOrImpl(span), - num_expected_regions).move_iter().collect()) + fcx.infcx().region_vars_for_defs(span, tpt.generics.region_param_defs.borrow().as_slice()) }; let regions = ty::NonerasedRegions(regions); diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index d0bb1f32fb8ff..c8a126382f4b4 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -21,12 +21,12 @@ use util::ppaux; // Helper functions related to manipulating region types. -pub fn replace_bound_regions_in_fn_sig( +pub fn replace_late_bound_regions_in_fn_sig( tcx: ty::ctxt, fn_sig: &ty::FnSig, mapf: |ty::BoundRegion| -> ty::Region) -> (HashMap, ty::FnSig) { - debug!("replace_bound_regions_in_fn_sig({})", fn_sig.repr(tcx)); + debug!("replace_late_bound_regions_in_fn_sig({})", fn_sig.repr(tcx)); let mut map = HashMap::new(); let fn_sig = { diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 32e1dfd98db57..57e85ab55d3bc 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -777,6 +777,7 @@ pub fn resolve_impl(tcx: ty::ctxt, impl_generics.type_param_defs(), [], impl_generics.region_param_defs(), + [], impl_item.id); let impl_trait_ref = @impl_trait_ref.subst(tcx, ¶m_env.free_substs); @@ -832,7 +833,7 @@ pub fn trans_resolve_method(tcx: ty::ctxt, id: ast::NodeId, if has_trait_bounds(type_param_defs.as_slice()) { let vcx = VtableContext { infcx: &infer::new_infer_ctxt(tcx), - param_env: &ty::construct_parameter_environment(tcx, None, [], [], [], id) + param_env: &ty::construct_parameter_environment(tcx, None, [], [], [], [], id) }; let loc_info = LocationInfo { id: id, diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index e85d71fa982ce..ca5befa8d4e06 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -42,7 +42,6 @@ use syntax::ast_map::NodeItem; use syntax::ast_map; use syntax::ast_util::{def_id_of_def, local_def}; use syntax::codemap::Span; -use syntax::opt_vec; use syntax::parse::token; use syntax::visit; @@ -516,18 +515,17 @@ impl CoherenceChecker { // type variables. Returns the monotype and the type variables created. fn universally_quantify_polytype(&self, polytype: ty_param_bounds_and_ty) -> UniversalQuantificationResult { - let region_parameter_count = polytype.generics.region_param_defs().len(); let region_parameters = - self.inference_context.next_region_vars( - infer::BoundRegionInCoherence, - region_parameter_count); + polytype.generics.region_param_defs().iter() + .map(|d| self.inference_context.next_region_var( + infer::BoundRegionInCoherence(d.name))) + .collect(); let bounds_count = polytype.generics.type_param_defs().len(); let type_parameters = self.inference_context.next_ty_vars(bounds_count); let substitutions = substs { - regions: ty::NonerasedRegions(opt_vec::from( - region_parameters.move_iter().collect())), + regions: ty::NonerasedRegions(region_parameters), self_ty: None, tps: type_parameters }; diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 18fbb47aad1b2..234e6e92bac9f 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -32,6 +32,7 @@ are represented as `ty_param()` instances. use metadata::csearch; +use middle::resolve_lifetime; use middle::ty::{ImplContainer, MethodContainer, TraitContainer, substs}; use middle::ty::{ty_param_bounds_and_ty}; use middle::ty; @@ -45,7 +46,6 @@ use util::ppaux; use util::ppaux::Repr; use std::rc::Rc; -use std::vec; use std::vec_ng::Vec; use std::vec_ng; use syntax::abi::AbiSet; @@ -160,7 +160,7 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt, ast::StructVariantKind(struct_def) => { let tpt = ty_param_bounds_and_ty { - generics: ty_generics(ccx, generics, 0), + generics: ty_generics_for_type(ccx, generics), ty: enum_ty }; @@ -173,7 +173,7 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt, }; let tpt = ty_param_bounds_and_ty { - generics: ty_generics(ccx, generics, 0), + generics: ty_generics_for_type(ccx, generics), ty: result_ty }; @@ -192,7 +192,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) { ast_map::NodeItem(item) => { match item.node { ast::ItemTrait(ref generics, _, ref ms) => { - let trait_ty_generics = ty_generics(ccx, generics, 0); + let trait_ty_generics = ty_generics_for_type(ccx, generics); // For each method, construct a suitable ty::Method and // store it into the `tcx.methods` table: @@ -293,7 +293,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) { // Represents [A',B',C'] let num_trait_bounds = trait_ty_generics.type_param_defs().len(); - let non_shifted_trait_tps = vec::from_fn(num_trait_bounds, |i| { + let non_shifted_trait_tps = Vec::from_fn(num_trait_bounds, |i| { ty::mk_param(tcx, i, trait_ty_generics.type_param_defs()[i].def_id) }); @@ -303,7 +303,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) { // Represents [E',F',G'] let num_method_bounds = m.generics.type_param_defs().len(); - let shifted_method_tps = vec::from_fn(num_method_bounds, |i| { + let shifted_method_tps = Vec::from_fn(num_method_bounds, |i| { ty::mk_param(tcx, i + num_trait_bounds + 1, m.generics.type_param_defs()[i].def_id) }); @@ -315,7 +315,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) { let rps_from_trait = trait_ty_generics.region_param_defs().iter(). enumerate(). - map(|(index,d)| ty::ReEarlyBound(d.def_id.node, index, d.ident)). + map(|(index,d)| ty::ReEarlyBound(d.def_id.node, index, d.name)). collect(); // build up the substitution from @@ -326,8 +326,8 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) { let substs = substs { regions: ty::NonerasedRegions(rps_from_trait), self_ty: Some(self_param), - tps: vec_ng::append(Vec::from_slice(non_shifted_trait_tps), - shifted_method_tps) + tps: vec_ng::append(non_shifted_trait_tps, + shifted_method_tps.as_slice()) }; // create the type of `foo`, applying the substitution above @@ -394,10 +394,11 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) { let fty = astconv::ty_of_method(this, *m_id, *m_purity, trait_self_ty, *m_explicit_self, m_decl); let num_trait_type_params = trait_generics.type_param_defs().len(); + let ty_generics = ty_generics_for_fn_or_method(this, m_generics, + num_trait_type_params); ty::Method::new( *m_ident, - // FIXME(#5121) -- distinguish early vs late lifetime params - ty_generics(this, m_generics, num_trait_type_params), + ty_generics, fty, m_explicit_self.node, // assume public, because this is only invoked on trait methods @@ -477,7 +478,8 @@ fn convert_methods(ccx: &CrateCtxt, let tcx = ccx.tcx; for m in ms.iter() { let num_rcvr_ty_params = rcvr_ty_generics.type_param_defs().len(); - let m_ty_generics = ty_generics(ccx, &m.generics, num_rcvr_ty_params); + let m_ty_generics = ty_generics_for_fn_or_method(ccx, &m.generics, + num_rcvr_ty_params); let mty = @ty_of_method(ccx, container, *m, @@ -503,7 +505,9 @@ fn convert_methods(ccx: &CrateCtxt, Vec::from_slice( rcvr_ty_generics.type_param_defs()), m_ty_generics.type_param_defs())), - region_param_defs: rcvr_ty_generics.region_param_defs.clone(), + region_param_defs: Rc::new(vec_ng::append( + Vec::from_slice(rcvr_ty_generics.region_param_defs()), + m_ty_generics.region_param_defs())), }, ty: fty }); @@ -533,10 +537,11 @@ fn convert_methods(ccx: &CrateCtxt, let method_vis = m.vis.inherit_from(rcvr_visibility); let num_rcvr_type_params = rcvr_generics.ty_params.len(); + let m_ty_generics = + ty_generics_for_fn_or_method(ccx, &m.generics, num_rcvr_type_params); ty::Method::new( m.ident, - // FIXME(#5121) -- distinguish early vs late lifetime params - ty_generics(ccx, &m.generics, num_rcvr_type_params), + m_ty_generics, fty, m.explicit_self.node, method_vis, @@ -588,7 +593,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { generics); }, ast::ItemImpl(ref generics, ref opt_trait_ref, selfty, ref ms) => { - let i_ty_generics = ty_generics(ccx, generics, 0); + let ty_generics = ty_generics_for_type(ccx, generics); let selfty = ccx.to_ty(&ExplicitRscope, selfty); write_ty_to_tcx(tcx, it.id, selfty); @@ -596,7 +601,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { let mut tcache = tcx.tcache.borrow_mut(); tcache.get().insert(local_def(it.id), ty_param_bounds_and_ty { - generics: i_ty_generics.clone(), + generics: ty_generics.clone(), ty: selfty}); } @@ -615,7 +620,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { ImplContainer(local_def(it.id)), ms.as_slice(), selfty, - &i_ty_generics, + &ty_generics, generics, parent_visibility); @@ -813,7 +818,7 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> @ty::TraitDef { match it.node { ast::ItemTrait(ref generics, ref supertraits, _) => { let self_ty = ty::mk_self(tcx, def_id); - let ty_generics = ty_generics(ccx, generics, 0); + let ty_generics = ty_generics_for_type(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics, Some(self_ty)); let bounds = ensure_supertraits(ccx, it.id, @@ -857,17 +862,14 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item) return tpt; } ast::ItemFn(decl, purity, abi, ref generics, _) => { - let ty_generics = ty_generics(ccx, generics, 0); + let ty_generics = ty_generics_for_fn_or_method(ccx, generics, 0); let tofd = astconv::ty_of_bare_fn(ccx, it.id, purity, abi, decl); let tpt = ty_param_bounds_and_ty { - generics: ty::Generics { - type_param_defs: ty_generics.type_param_defs.clone(), - region_param_defs: Rc::new(Vec::new()), - }, + generics: ty_generics, ty: ty::mk_bare_fn(ccx.tcx, tofd) }; debug!("type of {} (id {}) is {}", @@ -891,7 +893,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item) let tpt = { let ty = ccx.to_ty(&ExplicitRscope, t); ty_param_bounds_and_ty { - generics: ty_generics(ccx, generics, 0), + generics: ty_generics_for_type(ccx, generics), ty: ty } }; @@ -902,7 +904,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item) } ast::ItemEnum(_, ref generics) => { // Create a new generic polytype. - let ty_generics = ty_generics(ccx, generics, 0); + let ty_generics = ty_generics_for_type(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics, None); let t = ty::mk_enum(tcx, local_def(it.id), substs); let tpt = ty_param_bounds_and_ty { @@ -920,7 +922,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item) format!("invoked ty_of_item on trait")); } ast::ItemStruct(_, ref generics) => { - let ty_generics = ty_generics(ccx, generics, 0); + let ty_generics = ty_generics_for_type(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics, None); let t = ty::mk_struct(tcx, local_def(it.id), substs); let tpt = ty_param_bounds_and_ty { @@ -961,42 +963,51 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt, } } +pub fn ty_generics_for_type(ccx: &CrateCtxt, + generics: &ast::Generics) + -> ty::Generics { + ty_generics(ccx, &generics.lifetimes, &generics.ty_params, 0) +} + +pub fn ty_generics_for_fn_or_method(ccx: &CrateCtxt, + generics: &ast::Generics, + base_index: uint) + -> ty::Generics { + let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics); + ty_generics(ccx, &early_lifetimes, &generics.ty_params, base_index) +} + pub fn ty_generics(ccx: &CrateCtxt, - generics: &ast::Generics, + lifetimes: &Vec, + ty_params: &OptVec, base_index: uint) -> ty::Generics { return ty::Generics { - region_param_defs: Rc::new(generics.lifetimes.iter().map(|l| { - ty::RegionParameterDef { ident: l.ident, + region_param_defs: Rc::new(lifetimes.iter().map(|l| { + ty::RegionParameterDef { name: l.name, def_id: local_def(l.id) } }).collect()), - type_param_defs: Rc::new(generics.ty_params.mapi_to_vec(|offset, param| { + type_param_defs: Rc::new(ty_params.mapi_to_vec(|offset, param| { let existing_def_opt = { let ty_param_defs = ccx.tcx.ty_param_defs.borrow(); - ty_param_defs.get().find(¶m.id).map(|def| *def) + ty_param_defs.get().find(¶m.id).map(|&def| def) }; - match existing_def_opt { - Some(def) => def, - None => { - let param_ty = ty::param_ty {idx: base_index + offset, - def_id: local_def(param.id)}; - let bounds = @compute_bounds(ccx, param_ty, ¶m.bounds); - let default = param.default.map(|x| ast_ty_to_ty(ccx, &ExplicitRscope, x)); - let def = ty::TypeParameterDef { - ident: param.ident, - def_id: local_def(param.id), - bounds: bounds, - default: default - }; - debug!("def for param: {}", def.repr(ccx.tcx)); - - let mut ty_param_defs = ccx.tcx - .ty_param_defs - .borrow_mut(); - ty_param_defs.get().insert(param.id, def); - def - } - } - }).move_iter().collect()) + existing_def_opt.unwrap_or_else(|| { + let param_ty = ty::param_ty {idx: base_index + offset, + def_id: local_def(param.id)}; + let bounds = @compute_bounds(ccx, param_ty, ¶m.bounds); + let default = param.default.map(|x| ast_ty_to_ty(ccx, &ExplicitRscope, x)); + let def = ty::TypeParameterDef { + ident: param.ident, + def_id: local_def(param.id), + bounds: bounds, + default: default + }; + debug!("def for param: {}", def.repr(ccx.tcx)); + let mut ty_param_defs = ccx.tcx.ty_param_defs.borrow_mut(); + ty_param_defs.get().insert(param.id, def); + def + }) + }).move_iter().collect()), }; fn compute_bounds( @@ -1056,7 +1067,8 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, } } - let ty_generics = ty_generics(ccx, ast_generics, 0); + let ty_generics_for_fn_or_method = + ty_generics_for_fn_or_method(ccx, ast_generics, 0); let rb = BindingRscope::new(def_id.node); let input_tys = decl.inputs .iter() @@ -1076,7 +1088,7 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, variadic: decl.variadic} }); let tpt = ty_param_bounds_and_ty { - generics: ty_generics, + generics: ty_generics_for_fn_or_method, ty: t_fn }; @@ -1095,7 +1107,7 @@ pub fn mk_item_substs(ccx: &CrateCtxt, let regions: OptVec = ty_generics.region_param_defs().iter().enumerate().map( - |(i, l)| ty::ReEarlyBound(l.def_id.node, i, l.ident)).collect(); + |(i, l)| ty::ReEarlyBound(l.def_id.node, i, l.name)).collect(); substs {regions: ty::NonerasedRegions(regions), self_ty: self_ty, diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index 3a3f24a2e2d88..0dea3460012c1 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -72,6 +72,7 @@ use middle::typeck::infer::region_inference::ConcreteFailure; use middle::typeck::infer::region_inference::SubSupConflict; use middle::typeck::infer::region_inference::SupSupConflict; use syntax::opt_vec::OptVec; +use syntax::parse::token; use util::ppaux::UserString; use util::ppaux::bound_region_to_str; use util::ppaux::note_and_explain_region; @@ -479,19 +480,21 @@ impl ErrorReportingHelpers for InferCtxt { infer::AddrOfSlice(_) => ~" for slice expression", infer::Autoref(_) => ~" for autoref", infer::Coercion(_) => ~" for automatic coercion", - infer::BoundRegionInFnCall(_, br) => { + infer::LateBoundRegion(_, br) => { format!(" for {}in function call", - bound_region_to_str(self.tcx, "region ", true, br)) + bound_region_to_str(self.tcx, "lifetime parameter ", true, br)) } infer::BoundRegionInFnType(_, br) => { format!(" for {}in function type", - bound_region_to_str(self.tcx, "region ", true, br)) + bound_region_to_str(self.tcx, "lifetime parameter ", true, br)) } - infer::BoundRegionInTypeOrImpl(_) => { - format!(" for region in type/impl") + infer::EarlyBoundRegion(_, name) => { + format!(" for lifetime parameter `{}", + token::get_name(name).get()) } - infer::BoundRegionInCoherence(..) => { - format!(" for coherence check") + infer::BoundRegionInCoherence(name) => { + format!(" for lifetime parameter `{} in coherence check", + token::get_name(name).get()) } infer::UpvarRegion(ref upvar_id, _) => { format!(" for capture of `{}` by closure", diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs index 68b609000f41b..ac73c30802557 100644 --- a/src/librustc/middle/typeck/infer/glb.rs +++ b/src/librustc/middle/typeck/infer/glb.rs @@ -136,11 +136,11 @@ impl<'f> Combine for Glb<'f> { // Instantiate each bound region with a fresh region variable. let (a_with_fresh, a_map) = - self.get_ref().infcx.replace_bound_regions_with_fresh_regions( + self.get_ref().infcx.replace_late_bound_regions_with_fresh_regions( self.get_ref().trace, a); let a_vars = var_ids(self, &a_map); let (b_with_fresh, b_map) = - self.get_ref().infcx.replace_bound_regions_with_fresh_regions( + self.get_ref().infcx.replace_late_bound_regions_with_fresh_regions( self.get_ref().trace, b); let b_vars = var_ids(self, &b_map); diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs index 0f2b2da397e9d..7d772065da61e 100644 --- a/src/librustc/middle/typeck/infer/lub.rs +++ b/src/librustc/middle/typeck/infer/lub.rs @@ -126,10 +126,10 @@ impl<'f> Combine for Lub<'f> { // Instantiate each bound region with a fresh region variable. let (a_with_fresh, a_map) = - self.get_ref().infcx.replace_bound_regions_with_fresh_regions( + self.get_ref().infcx.replace_late_bound_regions_with_fresh_regions( self.get_ref().trace, a); let (b_with_fresh, _) = - self.get_ref().infcx.replace_bound_regions_with_fresh_regions( + self.get_ref().infcx.replace_late_bound_regions_with_fresh_regions( self.get_ref().trace, b); // Collect constraints. diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 5500d9afc6750..d3ae7d697e699 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -27,7 +27,7 @@ use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, Vid}; use middle::ty; use middle::ty_fold; use middle::ty_fold::TypeFolder; -use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig; +use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; use middle::typeck::infer::coercion::Coerce; use middle::typeck::infer::combine::{Combine, CombineFields, eq_tys}; use middle::typeck::infer::region_inference::{RegionVarBindings}; @@ -44,6 +44,7 @@ use syntax::ast::{MutImmutable, MutMutable}; use syntax::ast; use syntax::codemap; use syntax::codemap::Span; +use syntax::opt_vec::OptVec; use util::common::indent; use util::ppaux::{bound_region_to_str, ty_to_str, trait_ref_to_str, Repr}; @@ -221,9 +222,12 @@ pub enum RegionVariableOrigin { // Regions created as part of an automatic coercion Coercion(TypeTrace), + // Region variables created as the values for early-bound regions + EarlyBoundRegion(Span, ast::Name), + // Region variables created for bound regions // in a function or method that is called - BoundRegionInFnCall(Span, ty::BoundRegion), + LateBoundRegion(Span, ty::BoundRegion), // Region variables created for bound regions // when doing subtyping/lub/glb computations @@ -231,9 +235,7 @@ pub enum RegionVariableOrigin { UpvarRegion(ty::UpvarId, Span), - BoundRegionInTypeOrImpl(Span), - - BoundRegionInCoherence, + BoundRegionInCoherence(ast::Name), } pub enum fixup_err { @@ -663,6 +665,15 @@ impl InferCtxt { Vec::from_fn(count, |_| self.next_region_var(origin)) } + pub fn region_vars_for_defs(&self, + span: Span, + defs: &[ty::RegionParameterDef]) + -> OptVec { + defs.iter() + .map(|d| self.next_region_var(EarlyBoundRegion(span, d.name))) + .collect() + } + pub fn fresh_bound_region(&self, binder_id: ast::NodeId) -> ty::Region { self.region_vars.new_bound(binder_id) } @@ -809,14 +820,14 @@ impl InferCtxt { self.type_error_message(sp, mk_msg, a, Some(err)); } - pub fn replace_bound_regions_with_fresh_regions(&self, - trace: TypeTrace, - fsig: &ty::FnSig) + pub fn replace_late_bound_regions_with_fresh_regions(&self, + trace: TypeTrace, + fsig: &ty::FnSig) -> (ty::FnSig, HashMap) { let (map, fn_sig) = - replace_bound_regions_in_fn_sig(self.tcx, fsig, |br| { + replace_late_bound_regions_in_fn_sig(self.tcx, fsig, |br| { let rvar = self.next_region_var( BoundRegionInFnType(trace.origin.span(), br)); debug!("Bound region {} maps to {:?}", @@ -932,10 +943,10 @@ impl RegionVariableOrigin { AddrOfSlice(a) => a, Autoref(a) => a, Coercion(a) => a.span(), - BoundRegionInFnCall(a, _) => a, + EarlyBoundRegion(a, _) => a, + LateBoundRegion(a, _) => a, BoundRegionInFnType(a, _) => a, - BoundRegionInTypeOrImpl(a) => a, - BoundRegionInCoherence => codemap::DUMMY_SP, + BoundRegionInCoherence(_) => codemap::DUMMY_SP, UpvarRegion(_, a) => a } } @@ -950,13 +961,14 @@ impl Repr for RegionVariableOrigin { AddrOfSlice(a) => format!("AddrOfSlice({})", a.repr(tcx)), Autoref(a) => format!("Autoref({})", a.repr(tcx)), Coercion(a) => format!("Coercion({})", a.repr(tcx)), - BoundRegionInFnCall(a, b) => format!("bound_regionInFnCall({},{})", + EarlyBoundRegion(a, b) => format!("EarlyBoundRegion({},{})", a.repr(tcx), b.repr(tcx)), + LateBoundRegion(a, b) => format!("LateBoundRegion({},{})", + a.repr(tcx), b.repr(tcx)), BoundRegionInFnType(a, b) => format!("bound_regionInFnType({},{})", a.repr(tcx), b.repr(tcx)), - BoundRegionInTypeOrImpl(a) => format!("bound_regionInTypeOrImpl({})", - a.repr(tcx)), - BoundRegionInCoherence => format!("bound_regionInCoherence"), + BoundRegionInCoherence(a) => format!("bound_regionInCoherence({})", + a.repr(tcx)), UpvarRegion(a, b) => format!("UpvarRegion({}, {})", a.repr(tcx), b.repr(tcx)), diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index 57953313324bc..2233e680bc99e 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -12,7 +12,7 @@ use middle::ty::{BuiltinBounds}; use middle::ty; use middle::ty::TyVar; -use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig; +use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; use middle::typeck::infer::combine::*; use middle::typeck::infer::{cres, CresCompare}; use middle::typeck::infer::glb::Glb; @@ -166,13 +166,13 @@ impl<'f> Combine for Sub<'f> { // First, we instantiate each bound region in the subtype with a fresh // region variable. let (a_sig, _) = - self.get_ref().infcx.replace_bound_regions_with_fresh_regions( + self.get_ref().infcx.replace_late_bound_regions_with_fresh_regions( self.get_ref().trace, a); // Second, we instantiate each bound region in the supertype with a // fresh concrete region. let (skol_map, b_sig) = { - replace_bound_regions_in_fn_sig(self.get_ref().infcx.tcx, b, |br| { + replace_late_bound_regions_in_fn_sig(self.get_ref().infcx.tcx, b, |br| { let skol = self.get_ref().infcx.region_vars.new_skolemized(br); debug!("Bound region {} skolemized to {:?}", bound_region_to_str(self.get_ref().infcx.tcx, "", false, br), diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs index eb633eb2eee01..078415bc64411 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc/middle/typeck/rscope.rs @@ -78,5 +78,5 @@ pub fn bound_type_regions(defs: &[ty::RegionParameterDef]) -> OptVec { assert!(defs.iter().all(|def| def.def_id.krate == ast::LOCAL_CRATE)); defs.iter().enumerate().map( - |(i, def)| ty::ReEarlyBound(def.def_id.node, i, def.ident)).collect() + |(i, def)| ty::ReEarlyBound(def.def_id.node, i, def.name)).collect() } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index ecba394b88e24..2f06ab67a3bab 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -161,8 +161,8 @@ pub fn bound_region_to_str(cx: ctxt, } match br { - BrNamed(_, ident) => format!("{}'{}{}", prefix, - token::get_name(ident), space_str), + BrNamed(_, name) => format!("{}'{}{}", prefix, + token::get_name(name), space_str), BrAnon(_) => prefix.to_str(), BrFresh(_) => prefix.to_str(), } @@ -224,7 +224,7 @@ pub fn region_to_str(cx: ctxt, prefix: &str, space: bool, region: Region) -> ~st // `explain_region()` or `note_and_explain_region()`. match region { ty::ReScope(_) => prefix.to_str(), - ty::ReEarlyBound(_, _, ident) => token::get_name(ident).get().to_str(), + ty::ReEarlyBound(_, _, name) => token::get_name(name).get().to_str(), ty::ReLateBound(_, br) => bound_region_to_str(cx, prefix, space, br), ty::ReFree(ref fr) => bound_region_to_str(cx, prefix, space, fr.bound_region), ty::ReInfer(ReSkolemized(_, br)) => { @@ -634,7 +634,7 @@ impl Repr for ty::TypeParameterDef { impl Repr for ty::RegionParameterDef { fn repr(&self, _tcx: ctxt) -> ~str { format!("RegionParameterDef({}, {:?})", - token::get_name(self.ident), + token::get_name(self.name), self.def_id) } } @@ -720,9 +720,9 @@ impl Repr for ty::BoundRegion { fn repr(&self, tcx: ctxt) -> ~str { match *self { ty::BrAnon(id) => format!("BrAnon({})", id), - ty::BrNamed(id, ident) => format!("BrNamed({}, {})", - id.repr(tcx), - token::get_name(ident)), + ty::BrNamed(id, name) => format!("BrNamed({}, {})", + id.repr(tcx), + token::get_name(name)), ty::BrFresh(id) => format!("BrFresh({})", id), } } @@ -731,9 +731,9 @@ impl Repr for ty::BoundRegion { impl Repr for ty::Region { fn repr(&self, tcx: ctxt) -> ~str { match *self { - ty::ReEarlyBound(id, index, ident) => { + ty::ReEarlyBound(id, index, name) => { format!("ReEarlyBound({}, {}, {})", - id, index, token::get_name(ident)) + id, index, token::get_name(name)) } ty::ReLateBound(binder_id, ref bound_region) => { @@ -841,6 +841,12 @@ impl Repr for ty::Method { } } +impl Repr for ast::Name { + fn repr(&self, _tcx: ctxt) -> ~str { + token::get_name(*self).get().to_str() + } +} + impl Repr for ast::Ident { fn repr(&self, _tcx: ctxt) -> ~str { token::get_ident(*self).get().to_str() @@ -1010,6 +1016,12 @@ impl UserString for ty::t { } } +impl UserString for ast::Ident { + fn user_string(&self, _tcx: ctxt) -> ~str { + token::get_name(self.name).get().to_owned() + } +} + impl Repr for AbiSet { fn repr(&self, _tcx: ctxt) -> ~str { self.to_str() diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index f26977e211ca2..625cc5bc62346 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -333,7 +333,7 @@ impl Lifetime { impl Clean for ast::Lifetime { fn clean(&self) -> Lifetime { - Lifetime(token::get_name(self.ident).get().to_owned()) + Lifetime(token::get_name(self.name).get().to_owned()) } } diff --git a/src/libstd/vec_ng.rs b/src/libstd/vec_ng.rs index 76fd68a526513..eed5143b7cff1 100644 --- a/src/libstd/vec_ng.rs +++ b/src/libstd/vec_ng.rs @@ -64,6 +64,26 @@ impl Vec { xs } } + + /** + * Partitions the vector into two vectors `(A,B)`, where all + * elements of `A` satisfy `f` and all elements of `B` do not. + */ + #[inline] + pub fn partition(self, f: |&T| -> bool) -> (Vec, Vec) { + let mut lefts = Vec::new(); + let mut rights = Vec::new(); + + for elt in self.move_iter() { + if f(&elt) { + lefts.push(elt); + } else { + rights.push(elt); + } + } + + (lefts, rights) + } } impl Vec { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 0a95999351757..b6b18f6671d31 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -118,7 +118,7 @@ pub type FnIdent = Option; pub struct Lifetime { id: NodeId, span: Span, - ident: Name + name: Name } // a "Path" is essentially Rust's notion of a name; @@ -142,7 +142,7 @@ pub struct PathSegment { /// The identifier portion of this path segment. identifier: Ident, /// The lifetime parameters for this path segment. - lifetimes: OptVec, + lifetimes: Vec, /// The type parameters for this path segment, if present. types: OptVec>, } @@ -187,7 +187,7 @@ pub struct TyParam { #[deriving(Clone, Eq, Encodable, Decodable, Hash)] pub struct Generics { - lifetimes: OptVec, + lifetimes: Vec, ty_params: OptVec, } @@ -795,7 +795,7 @@ impl fmt::Show for Onceness { pub struct ClosureTy { sigil: Sigil, region: Option, - lifetimes: OptVec, + lifetimes: Vec, purity: Purity, onceness: Onceness, decl: P, @@ -810,7 +810,7 @@ pub struct ClosureTy { pub struct BareFnTy { purity: Purity, abis: AbiSet, - lifetimes: OptVec, + lifetimes: Vec, decl: P } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index a6e3111fe3f76..d45ea2067924b 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -195,7 +195,7 @@ pub fn ident_to_path(s: Span, identifier: Ident) -> Path { segments: vec!( ast::PathSegment { identifier: identifier, - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, } ), @@ -311,7 +311,7 @@ pub fn operator_prec(op: ast::BinOp) -> uint { pub static as_prec: uint = 12u; pub fn empty_generics() -> Generics { - Generics {lifetimes: opt_vec::Empty, + Generics {lifetimes: Vec::new(), ty_params: opt_vec::Empty} } @@ -690,10 +690,11 @@ mod test { use ast::*; use super::*; use opt_vec; + use std::vec_ng::Vec; fn ident_to_segment(id : &Ident) -> PathSegment { PathSegment {identifier:id.clone(), - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty} } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 8296ee34c5452..6aa90e5e8428a 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -42,7 +42,7 @@ pub trait AstBuilder { fn path_all(&self, sp: Span, global: bool, idents: Vec , - lifetimes: OptVec, + lifetimes: Vec, types: Vec> ) -> ast::Path; @@ -255,19 +255,19 @@ pub trait AstBuilder { impl<'a> AstBuilder for ExtCtxt<'a> { fn path(&self, span: Span, strs: Vec ) -> ast::Path { - self.path_all(span, false, strs, opt_vec::Empty, Vec::new()) + self.path_all(span, false, strs, Vec::new(), Vec::new()) } fn path_ident(&self, span: Span, id: ast::Ident) -> ast::Path { self.path(span, vec!(id)) } fn path_global(&self, span: Span, strs: Vec ) -> ast::Path { - self.path_all(span, true, strs, opt_vec::Empty, Vec::new()) + self.path_all(span, true, strs, Vec::new(), Vec::new()) } fn path_all(&self, sp: Span, global: bool, mut idents: Vec , - lifetimes: OptVec, + lifetimes: Vec, types: Vec> ) -> ast::Path { let last_identifier = idents.pop().unwrap(); @@ -275,7 +275,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { .map(|ident| { ast::PathSegment { identifier: ident, - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, } }).collect(); @@ -342,7 +342,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.ident_of("option"), self.ident_of("Option") ), - opt_vec::Empty, + Vec::new(), vec!( ty )), None) } @@ -413,8 +413,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> { ast::TraitTyParamBound(self.trait_ref(path)) } - fn lifetime(&self, span: Span, ident: ast::Name) -> ast::Lifetime { - ast::Lifetime { id: ast::DUMMY_NODE_ID, span: span, ident: ident } + fn lifetime(&self, span: Span, name: ast::Name) -> ast::Lifetime { + ast::Lifetime { id: ast::DUMMY_NODE_ID, span: span, name: name } } fn stmt_expr(&self, expr: @ast::Expr) -> @ast::Stmt { diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index 2552586939811..ee3adb7aad890 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -15,6 +15,7 @@ use ext::base; use opt_vec; use parse::token; use parse::token::{str_to_ident}; +use std::vec_ng::Vec; pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult { @@ -51,7 +52,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) segments: vec!( ast::PathSegment { identifier: res, - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, } ) diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index 2d16c87b78b19..b8ef9d98b2935 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -14,7 +14,6 @@ use codemap::Span; use ext::base::ExtCtxt; use ext::build::{AstBuilder}; use ext::deriving::generic::*; -use opt_vec; use std::vec_ng::Vec; @@ -84,7 +83,7 @@ fn rand_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) let rand_name = cx.path_all(trait_span, true, rand_ident.clone(), - opt_vec::Empty, + Vec::new(), Vec::new()); let rand_name = cx.expr_path(rand_name); diff --git a/src/libsyntax/ext/deriving/ty.rs b/src/libsyntax/ext/deriving/ty.rs index b88cd117911c7..60166f30f1ef9 100644 --- a/src/libsyntax/ext/deriving/ty.rs +++ b/src/libsyntax/ext/deriving/ty.rs @@ -19,7 +19,6 @@ use ext::base::ExtCtxt; use ext::build::AstBuilder; use codemap::{Span,respan}; use opt_vec; -use opt_vec::OptVec; use std::vec_ng::Vec; @@ -118,11 +117,12 @@ fn mk_lifetime(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Option) -> OptVec { - match *lt { +fn mk_lifetimes(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Vec { + let lifetimes = match *lt { Some(ref s) => opt_vec::with(cx.lifetime(span, cx.ident_of(*s).name)), None => opt_vec::Empty - } + }; + opt_vec::take_vec(lifetimes) } impl<'a> Ty<'a> { @@ -199,7 +199,7 @@ fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, bounds: &[Path], fn mk_generics(lifetimes: Vec , ty_params: Vec ) -> Generics { Generics { - lifetimes: opt_vec::from(lifetimes), + lifetimes: lifetimes, ty_params: opt_vec::from(ty_params) } } diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs index b0b5fa26015cc..0c7b92d0373cc 100644 --- a/src/libsyntax/ext/env.rs +++ b/src/libsyntax/ext/env.rs @@ -19,10 +19,10 @@ use codemap::Span; use ext::base::*; use ext::base; use ext::build::AstBuilder; -use opt_vec; use parse::token; use std::os; +use std::vec_ng::Vec; pub fn expand_option_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult { @@ -38,7 +38,7 @@ pub fn expand_option_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) vec!(cx.ident_of("std"), cx.ident_of("option"), cx.ident_of("None")), - opt_vec::Empty, + Vec::new(), vec!(cx.ty_rptr(sp, cx.ty_ident(sp, cx.ident_of("str")), diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index b27ea3df21ec0..0db948c30b7c4 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -14,7 +14,6 @@ use codemap::{Span, respan}; use ext::base::*; use ext::base; use ext::build::AstBuilder; -use opt_vec; use parse::token::InternedString; use parse::token; use rsparse = parse; @@ -509,7 +508,7 @@ impl<'a> Context<'a> { sp, true, self.rtpath("Method"), - opt_vec::with(life), + vec!(life), Vec::new() ), None); let st = ast::ItemStatic(ty, ast::MutImmutable, method); @@ -632,8 +631,8 @@ impl<'a> Context<'a> { self.ecx.ident_of("fmt"), self.ecx.ident_of("rt"), self.ecx.ident_of("Piece")), - opt_vec::with( - self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static").name)), + vec!(self.ecx.lifetime(self.fmtsp, + self.ecx.ident_of("static").name)), Vec::new() ), None); let ty = ast::TyFixedLengthVec( diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index df6b06c5804de..0b56cd07c887f 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -435,12 +435,12 @@ pub fn fold_lifetime(l: &Lifetime, fld: &mut T) -> Lifetime { Lifetime { id: fld.new_id(l.id), span: fld.new_span(l.span), - ident: l.ident + name: l.name } } -pub fn fold_lifetimes(lts: &OptVec, fld: &mut T) - -> OptVec { +pub fn fold_lifetimes(lts: &Vec, fld: &mut T) + -> Vec { lts.map(|l| fold_lifetime(l, fld)) } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 9e5db1770bf31..cb49ad0905cda 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -323,7 +323,7 @@ mod test { segments: vec!( ast::PathSegment { identifier: str_to_ident("a"), - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, } ), @@ -342,12 +342,12 @@ mod test { segments: vec!( ast::PathSegment { identifier: str_to_ident("a"), - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, }, ast::PathSegment { identifier: str_to_ident("b"), - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, } ) @@ -556,7 +556,7 @@ mod test { segments: vec!( ast::PathSegment { identifier: str_to_ident("d"), - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, } ), @@ -578,7 +578,7 @@ mod test { segments: vec!( ast::PathSegment { identifier: str_to_ident("b"), - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, } ), @@ -605,7 +605,7 @@ mod test { segments: vec!( ast::PathSegment { identifier: str_to_ident("b"), - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, } ), @@ -633,7 +633,7 @@ mod test { ast::PathSegment { identifier: str_to_ident("int"), - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, } ), @@ -651,7 +651,7 @@ mod test { ast::PathSegment { identifier: str_to_ident("b"), - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, } ), @@ -671,7 +671,7 @@ mod test { ast::ImpureFn, abi::AbiSet::Rust(), ast::Generics{ // no idea on either of these: - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), ty_params: opt_vec::Empty, }, ast::P(ast::Block { @@ -689,7 +689,7 @@ mod test { str_to_ident( "b"), lifetimes: - opt_vec::Empty, + Vec::new(), types: opt_vec::Empty } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c8bd87024e882..7760ca89eb271 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -958,7 +958,7 @@ impl Parser { lifetimes } else { - opt_vec::Empty + Vec::new() }; let inputs = if self.eat(&token::OROR) { @@ -1015,7 +1015,7 @@ impl Parser { // parse a function type (following the 'fn') pub fn parse_ty_fn_decl(&mut self, allow_variadic: bool) - -> (P, OptVec) { + -> (P, Vec) { /* (fn) <'lt> (S) -> T @@ -1031,7 +1031,7 @@ impl Parser { self.expect_gt(); lifetimes } else { - opt_vec::Empty + Vec::new() }; let (inputs, variadic) = self.parse_fn_args(false, allow_variadic); @@ -1510,7 +1510,7 @@ impl Parser { segments.push(PathSegmentAndBoundSet { segment: ast::PathSegment { identifier: identifier, - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, }, bound_set: bound_set @@ -1525,7 +1525,7 @@ impl Parser { self.parse_generic_values_after_lt(); (true, lifetimes, opt_vec::from(types)) } else { - (false, opt_vec::Empty, opt_vec::Empty) + (false, Vec::new(), opt_vec::Empty) } }; @@ -1609,7 +1609,7 @@ impl Parser { return ast::Lifetime { id: ast::DUMMY_NODE_ID, span: span, - ident: i.name + name: i.name }; } _ => { @@ -1621,7 +1621,7 @@ impl Parser { // matches lifetimes = ( lifetime ) | ( lifetime , lifetimes ) // actually, it matches the empty one too, but putting that in there // messes up the grammar.... - pub fn parse_lifetimes(&mut self) -> OptVec { + pub fn parse_lifetimes(&mut self) -> Vec { /*! * * Parses zero or more comma separated lifetimes. @@ -1630,7 +1630,7 @@ impl Parser { * lists, where we expect something like `<'a, 'b, T>`. */ - let mut res = opt_vec::Empty; + let mut res = Vec::new(); loop { match self.token { token::LIFETIME(_) => { @@ -1995,7 +1995,7 @@ impl Parser { self.expect(&token::LT); self.parse_generic_values_after_lt() } else { - (opt_vec::Empty, Vec::new()) + (Vec::new(), Vec::new()) }; // expr.f() method call @@ -3515,7 +3515,7 @@ impl Parser { } } - fn parse_generic_values_after_lt(&mut self) -> (OptVec, Vec> ) { + fn parse_generic_values_after_lt(&mut self) -> (Vec, Vec> ) { let lifetimes = self.parse_lifetimes(); let result = self.parse_seq_to_gt( Some(token::COMMA), @@ -4886,7 +4886,7 @@ impl Parser { segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, } }).collect() @@ -4921,7 +4921,7 @@ impl Parser { segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, } }).collect() @@ -4939,7 +4939,7 @@ impl Parser { segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, } }).collect() @@ -4961,7 +4961,7 @@ impl Parser { segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), types: opt_vec::Empty, } }).collect() diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index aafda9d687d85..45ab4c6956a49 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1956,7 +1956,7 @@ pub fn print_bounds(s: &mut State, bounds: &OptVec, pub fn print_lifetime(s: &mut State, lifetime: &ast::Lifetime) -> io::IoResult<()> { try!(word(&mut s.s, "'")); - print_name(s, lifetime.ident) + print_name(s, lifetime.name) } pub fn print_generics(s: &mut State, diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index f8a07599420e8..538528fb1484a 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -15,6 +15,7 @@ use codemap::Span; use parse; use opt_vec; use opt_vec::OptVec; +use std::vec_ng::Vec; // Context-passing AST walker. Each overridden visit method has full control // over what happens with its node, it can do its own traversal of the node's @@ -55,7 +56,7 @@ pub fn generics_of_fn(fk: &FnKind) -> Generics { } FkFnBlock(..) => { Generics { - lifetimes: opt_vec::Empty, + lifetimes: Vec::new(), ty_params: opt_vec::Empty, } } @@ -370,7 +371,7 @@ pub fn walk_ty>(visitor: &mut V, typ: &Ty, env: E) { } fn walk_lifetime_decls>(visitor: &mut V, - lifetimes: &OptVec, + lifetimes: &Vec, env: E) { for l in lifetimes.iter() { visitor.visit_lifetime_decl(l, env.clone()); diff --git a/src/test/compile-fail/regions-early-bound-error-method.rs b/src/test/compile-fail/regions-early-bound-error-method.rs new file mode 100644 index 0000000000000..9c8f8f8c30cc5 --- /dev/null +++ b/src/test/compile-fail/regions-early-bound-error-method.rs @@ -0,0 +1,35 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that you can use a fn lifetime parameter as part of +// the value for a type parameter in a bound. + +trait GetRef<'a> { + fn get(&self) -> &'a int; +} + +struct Box<'a> { + t: &'a int +} + +impl<'a> GetRef<'a> for Box<'a> { + fn get(&self) -> &'a int { + self.t + } +} + +impl<'a> Box<'a> { + fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a int { + g2.get() //~ ERROR lifetime mismatch + } +} + +fn main() { +} diff --git a/src/test/compile-fail/regions-early-bound-error.rs b/src/test/compile-fail/regions-early-bound-error.rs new file mode 100644 index 0000000000000..9cff4849cbeb2 --- /dev/null +++ b/src/test/compile-fail/regions-early-bound-error.rs @@ -0,0 +1,33 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that you can use a fn lifetime parameter as part of +// the value for a type parameter in a bound. + +trait GetRef<'a, T> { + fn get(&self) -> &'a T; +} + +struct Box<'a, T> { + t: &'a T +} + +impl<'a,T:Clone> GetRef<'a,T> for Box<'a,T> { + fn get(&self) -> &'a T { + self.t + } +} + +fn get<'a,'b,G:GetRef<'a, int>>(g1: G, b: &'b int) -> &'b int { + g1.get() //~ ERROR lifetime mismatch +} + +fn main() { +} diff --git a/src/test/run-pass/regions-early-bound-used-in-bound-method.rs b/src/test/run-pass/regions-early-bound-used-in-bound-method.rs new file mode 100644 index 0000000000000..c011d11749b60 --- /dev/null +++ b/src/test/run-pass/regions-early-bound-used-in-bound-method.rs @@ -0,0 +1,37 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that you can use a fn lifetime parameter as part of +// the value for a type parameter in a bound. + +trait GetRef<'a> { + fn get(&self) -> &'a int; +} + +struct Box<'a> { + t: &'a int +} + +impl<'a> GetRef<'a> for Box<'a> { + fn get(&self) -> &'a int { + self.t + } +} + +impl<'a> Box<'a> { + fn add<'b,G:GetRef<'b>>(&self, g2: G) -> int { + *self.t + *g2.get() + } +} + +pub fn main() { + let b1 = Box { t: &3 }; + assert_eq!(b1.add(b1), 6); +} diff --git a/src/test/run-pass/regions-early-bound-used-in-bound.rs b/src/test/run-pass/regions-early-bound-used-in-bound.rs new file mode 100644 index 0000000000000..22ea87c8d2809 --- /dev/null +++ b/src/test/run-pass/regions-early-bound-used-in-bound.rs @@ -0,0 +1,35 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that you can use a fn lifetime parameter as part of +// the value for a type parameter in a bound. + +trait GetRef<'a, T> { + fn get(&self) -> &'a T; +} + +struct Box<'a, T> { + t: &'a T +} + +impl<'a,T:Clone> GetRef<'a,T> for Box<'a,T> { + fn get(&self) -> &'a T { + self.t + } +} + +fn add<'a,G:GetRef<'a, int>>(g1: G, g2: G) -> int { + *g1.get() + *g2.get() +} + +pub fn main() { + let b1 = Box { t: &3 }; + assert_eq!(add(b1, b1), 6); +} diff --git a/src/test/run-pass/regions-early-bound-used-in-type-param.rs b/src/test/run-pass/regions-early-bound-used-in-type-param.rs new file mode 100644 index 0000000000000..592f482239385 --- /dev/null +++ b/src/test/run-pass/regions-early-bound-used-in-type-param.rs @@ -0,0 +1,35 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that you can use a fn lifetime parameter as part of +// the value for a type parameter in a bound. + +trait Get { + fn get(&self) -> T; +} + +struct Box { + t: T +} + +impl Get for Box { + fn get(&self) -> T { + self.t.clone() + } +} + +fn add<'a,G:Get<&'a int>>(g1: G, g2: G) -> int { + *g1.get() + *g2.get() +} + +pub fn main() { + let b1 = Box { t: &3 }; + assert_eq!(add(b1, b1), 6); +}