From da19563dbce08e2a78720010fe458007baa3703a Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 6 Mar 2014 23:33:46 +0100 Subject: [PATCH 1/6] Port partition method from ~[T] to Vec, for use early-late lifetime code. --- src/libstd/vec_ng.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) 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 { From 460ca4f037e4896f103889b694dd2971e3141eac Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 5 Mar 2014 06:59:35 +0100 Subject: [PATCH 2/6] Alpha-rename `.ident` fields of type `Name` to `.name`. --- src/librustc/metadata/decoder.rs | 2 +- src/librustc/metadata/encoder.rs | 2 +- src/librustc/metadata/tyencode.rs | 8 ++++---- src/librustc/middle/ty.rs | 4 ++-- src/librustc/middle/typeck/check/mod.rs | 2 +- src/librustc/middle/typeck/collect.rs | 6 +++--- src/librustc/middle/typeck/rscope.rs | 2 +- src/librustc/util/ppaux.rs | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) 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/ty.rs b/src/librustc/middle/ty.rs index 4d0f6704379d5..5129d7a8b684a 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, } @@ -5107,7 +5107,7 @@ pub fn construct_parameter_environment( 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)})). + bound_region: ty::BrNamed(r.def_id, r.name)})). collect(); let free_substs = substs { diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 3c98f3defd6e6..e0b6fc4597cee 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -901,7 +901,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()), diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 18fbb47aad1b2..04f37c95b07be 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -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 @@ -966,7 +966,7 @@ pub fn ty_generics(ccx: &CrateCtxt, base_index: uint) -> ty::Generics { return ty::Generics { region_param_defs: Rc::new(generics.lifetimes.iter().map(|l| { - ty::RegionParameterDef { ident: l.ident, + ty::RegionParameterDef { name: l.ident, def_id: local_def(l.id) } }).collect()), type_param_defs: Rc::new(generics.ty_params.mapi_to_vec(|offset, param| { @@ -1095,7 +1095,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/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..83877e1710adb 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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) } } From 189c0085d19c2cbd8e3b6ca8274e2cab60aad515 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 7 Mar 2014 03:10:52 +0100 Subject: [PATCH 3/6] alpha-rename .ident to .name in Lifetime, including in rustdoc. --- src/librustc/middle/resolve_lifetime.rs | 14 +++++++------- src/librustc/middle/typeck/astconv.rs | 6 +++--- src/librustc/middle/typeck/collect.rs | 2 +- src/librustc/util/ppaux.rs | 16 ++++++++-------- src/librustdoc/clean.rs | 2 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/ext/build.rs | 4 ++-- src/libsyntax/fold.rs | 2 +- src/libsyntax/parse/mod.rs | 6 +++--- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax/print/pprust.rs | 2 +- 11 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index c8e28d45e3cf1..784b0cdab3d0a 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -145,7 +145,7 @@ 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 { + if lifetime_ref.name == special_idents::statik.name { self.insert_lifetime(lifetime_ref, ast::DefStaticRegion); return; } @@ -262,7 +262,7 @@ 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) { @@ -271,23 +271,23 @@ impl LifetimeContext { 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))); } } } @@ -315,7 +315,7 @@ fn search_lifetimes(lifetimes: &OptVec, 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)); } } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 40e836ac0d9ad..085a8a4efeb5c 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) }) } }; diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 04f37c95b07be..82246899fb77c 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -966,7 +966,7 @@ pub fn ty_generics(ccx: &CrateCtxt, base_index: uint) -> ty::Generics { return ty::Generics { region_param_defs: Rc::new(generics.lifetimes.iter().map(|l| { - ty::RegionParameterDef { name: l.ident, + 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| { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 83877e1710adb..c6765bd305acb 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)) => { @@ -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) => { 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/libsyntax/ast.rs b/src/libsyntax/ast.rs index 0a95999351757..372641af5f824 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; diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 8296ee34c5452..e644eca8f7db5 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -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/fold.rs b/src/libsyntax/fold.rs index df6b06c5804de..99e7b6a7ab14d 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -435,7 +435,7 @@ 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 } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 9e5db1770bf31..b6f813269cf88 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, } ) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c8bd87024e882..f80fc78b79c5f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1609,7 +1609,7 @@ impl Parser { return ast::Lifetime { id: ast::DUMMY_NODE_ID, span: span, - ident: i.name + name: i.name }; } _ => { 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, From 28ebec516015eb0b9cef05e5da0685a18620b105 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 26 Feb 2014 14:59:49 +0100 Subject: [PATCH 4/6] Introduce Scope<'a> shorthand for &'a ScopeChain<'a>. --- src/librustc/middle/resolve_lifetime.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 784b0cdab3d0a..90069cf899bb6 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -40,11 +40,13 @@ struct LifetimeContext { enum ScopeChain<'a> { ItemScope(&'a OptVec), - FnScope(ast::NodeId, &'a OptVec, &'a ScopeChain<'a>), - BlockScope(ast::NodeId, &'a ScopeChain<'a>), + FnScope(ast::NodeId, &'a OptVec, Scope<'a>), + 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 +58,10 @@ 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 scope = match item.node { ast::ItemFn(..) | // fn lifetimes get added in visit_fn below ast::ItemMod(..) | @@ -84,7 +86,7 @@ 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, _) => { @@ -101,7 +103,7 @@ impl<'a> Visitor<&'a ScopeChain<'a>> for LifetimeContext { } fn visit_ty(&mut self, ty: &ast::Ty, - scope: &'a ScopeChain<'a>) { + scope: Scope<'a>) { match ty.node { ast::TyClosure(closure) => { let scope1 = FnScope(ty.id, &closure.lifetimes, scope); @@ -125,7 +127,7 @@ impl<'a> Visitor<&'a ScopeChain<'a>> for LifetimeContext { fn visit_ty_method(&mut self, m: &ast::TypeMethod, - scope: &'a ScopeChain<'a>) { + scope: Scope<'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); @@ -135,7 +137,7 @@ impl<'a> Visitor<&'a ScopeChain<'a>> for LifetimeContext { 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,7 +146,7 @@ impl<'a> Visitor<&'a ScopeChain<'a>> for LifetimeContext { fn visit_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime, - scope: &'a ScopeChain<'a>) { + scope: Scope<'a>) { if lifetime_ref.name == special_idents::statik.name { self.insert_lifetime(lifetime_ref, ast::DefStaticRegion); return; @@ -156,7 +158,7 @@ impl<'a> Visitor<&'a ScopeChain<'a>> for LifetimeContext { impl LifetimeContext { 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 @@ -211,7 +213,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. From 586b619c76a3e5798283408954a0306d86ebc1ef Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 7 Mar 2014 16:50:40 +0100 Subject: [PATCH 5/6] Changed lists of lifetimes in ast and ty to use Vec instead of OptVec. There is a broader revision (that does this across the board) pending in #12675, but that is awaiting the arrival of more data (to decide whether to keep OptVec alive by using a non-Vec internally). For this code, the representation of lifetime lists needs to be the same in both ScopeChain and in the ast and ty structures. So it seemed cleanest to just use `vec_ng::Vec`, now that it has a cheaper empty representation than the current `vec` code. --- src/librustc/front/std_inject.rs | 4 ++-- src/librustc/front/test.rs | 4 ++-- src/librustc/middle/privacy.rs | 3 ++- src/librustc/middle/resolve_lifetime.rs | 10 +++++----- src/librustc/middle/trans/debuginfo.rs | 2 +- src/librustc/middle/typeck/astconv.rs | 8 ++++---- src/librustc/middle/typeck/check/mod.rs | 9 ++++----- src/libsyntax/ast.rs | 8 ++++---- src/libsyntax/ast_util.rs | 7 ++++--- src/libsyntax/ext/build.rs | 12 ++++++------ src/libsyntax/ext/concat_idents.rs | 3 ++- src/libsyntax/ext/deriving/rand.rs | 3 +-- src/libsyntax/ext/deriving/ty.rs | 10 +++++----- src/libsyntax/ext/env.rs | 4 ++-- src/libsyntax/ext/format.rs | 7 +++---- src/libsyntax/fold.rs | 4 ++-- src/libsyntax/parse/mod.rs | 14 ++++++------- src/libsyntax/parse/parser.rs | 26 ++++++++++++------------- src/libsyntax/visit.rs | 5 +++-- 19 files changed, 72 insertions(+), 71 deletions(-) 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/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 90069cf899bb6..6a55b05b77ec9 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -19,10 +19,10 @@ 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::OptVec; use syntax::parse::token::special_idents; use syntax::parse::token; use syntax::print::pprust::{lifetime_to_str}; @@ -39,8 +39,8 @@ struct LifetimeContext { } enum ScopeChain<'a> { - ItemScope(&'a OptVec), - FnScope(ast::NodeId, &'a OptVec, Scope<'a>), + ItemScope(&'a Vec), + FnScope(ast::NodeId, &'a Vec, Scope<'a>), BlockScope(ast::NodeId, Scope<'a>), RootScope } @@ -267,7 +267,7 @@ impl LifetimeContext { 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); @@ -313,7 +313,7 @@ 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() { 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/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 085a8a4efeb5c..e8770f9d142cf 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -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/mod.rs b/src/librustc/middle/typeck/check/mod.rs index e0b6fc4597cee..b10e1bcd5def2 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1453,8 +1453,7 @@ pub fn impl_self_ty(vcx: &VtableContext, 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(opt_vec::from(rps.move_iter().collect())), self_ty: None, tps: tps, }; @@ -3741,11 +3740,11 @@ pub fn instantiate_path(fcx: @FnCtxt, nsupplied = num_supplied_regions)); } - opt_vec::from(fcx.infcx().next_region_vars( + fcx.infcx().next_region_vars( infer::BoundRegionInTypeOrImpl(span), - num_expected_regions).move_iter().collect()) + num_expected_regions).move_iter().collect() }; - let regions = ty::NonerasedRegions(regions); + let regions = ty::NonerasedRegions(opt_vec::from(regions)); // Special case: If there is a self parameter, omit it from the list of // type parameters. diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 372641af5f824..b6b18f6671d31 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -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 e644eca8f7db5..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) } 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 99e7b6a7ab14d..0b56cd07c887f 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -439,8 +439,8 @@ pub fn fold_lifetime(l: &Lifetime, fld: &mut T) -> Lifetime { } } -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 b6f813269cf88..cb49ad0905cda 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -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 f80fc78b79c5f..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) } }; @@ -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/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()); From 742e458102ff5236ecf24a05ab94898c76d6d1cf Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 7 Mar 2014 08:43:39 +0100 Subject: [PATCH 6/6] Add proper support for early/late distinction for lifetime bindings. Uses newly added Vec::partition method to simplify resolve_lifetime. --- src/librustc/middle/resolve_lifetime.rs | 208 ++++++++++++++---- src/librustc/middle/subst.rs | 2 +- src/librustc/middle/ty.rs | 34 ++- src/librustc/middle/typeck/check/method.rs | 63 ++++-- src/librustc/middle/typeck/check/mod.rs | 56 ++--- .../middle/typeck/check/regionmanip.rs | 4 +- src/librustc/middle/typeck/check/vtable.rs | 3 +- src/librustc/middle/typeck/coherence.rs | 12 +- src/librustc/middle/typeck/collect.rs | 122 +++++----- .../middle/typeck/infer/error_reporting.rs | 17 +- src/librustc/middle/typeck/infer/glb.rs | 4 +- src/librustc/middle/typeck/infer/lub.rs | 4 +- src/librustc/middle/typeck/infer/mod.rs | 44 ++-- src/librustc/middle/typeck/infer/sub.rs | 6 +- src/librustc/util/ppaux.rs | 12 + .../regions-early-bound-error-method.rs | 35 +++ .../compile-fail/regions-early-bound-error.rs | 33 +++ ...egions-early-bound-used-in-bound-method.rs | 37 ++++ .../regions-early-bound-used-in-bound.rs | 35 +++ .../regions-early-bound-used-in-type-param.rs | 35 +++ 20 files changed, 566 insertions(+), 200 deletions(-) create mode 100644 src/test/compile-fail/regions-early-bound-error-method.rs create mode 100644 src/test/compile-fail/regions-early-bound-error.rs create mode 100644 src/test/run-pass/regions-early-bound-used-in-bound-method.rs create mode 100644 src/test/run-pass/regions-early-bound-used-in-bound.rs create mode 100644 src/test/run-pass/regions-early-bound-used-in-type-param.rs diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 6a55b05b77ec9..88eaf256be8cf 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -23,6 +23,8 @@ 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; use syntax::print::pprust::{lifetime_to_str}; @@ -33,14 +35,25 @@ 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 Vec), - FnScope(ast::NodeId, &'a Vec, Scope<'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 } @@ -62,6 +75,7 @@ impl<'a> Visitor> for LifetimeContext { fn visit_item(&mut self, item: &ast::Item, _: Scope<'a>) { + let root = RootScope; let scope = match item.node { ast::ItemFn(..) | // fn lifetimes get added in visit_fn below ast::ItemMod(..) | @@ -76,7 +90,7 @@ impl<'a> Visitor> 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); @@ -90,49 +104,41 @@ impl<'a> Visitor> for LifetimeContext { 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: Scope<'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: Scope<'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); + self.visit_fn_decl( + m.id, &m.generics, scope, + |this, scope1| visit::walk_ty_method(this, m, scope1)) } fn visit_block(&mut self, @@ -155,7 +161,82 @@ impl<'a> Visitor> 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: Scope) { @@ -177,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; } @@ -231,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; @@ -323,3 +402,44 @@ fn search_lifetimes(lifetimes: &Vec, } 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/ty.rs b/src/librustc/middle/ty.rs index 5129d7a8b684a..b2a879b1946e1 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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.name)})). - 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/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 b10e1bcd5def2..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 @@ -1439,21 +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, }; @@ -1887,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. @@ -2213,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, @@ -2461,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 }; @@ -2519,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 }; @@ -3726,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( @@ -3740,11 +3732,9 @@ pub fn instantiate_path(fcx: @FnCtxt, nsupplied = num_supplied_regions)); } - 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(opt_vec::from(regions)); + let regions = ty::NonerasedRegions(regions); // Special case: If there is a self parameter, omit it from the list of // type parameters. 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 82246899fb77c..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) }); @@ -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| { + 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 }; 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/util/ppaux.rs b/src/librustc/util/ppaux.rs index c6765bd305acb..2f06ab67a3bab 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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/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); +}