diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index da7f026aed4f5..fdc976ab5c847 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -1972,6 +1972,7 @@ impl + PartialOrd + Clone + ToPrimitive> Iterator for Range { // the i64/u64 might lie within their range. let bound = match self.state.to_i64() { Some(a) => { + let a = a; let sz = self.stop.to_i64().map(|b| b.checked_sub(&a)); match sz { Some(Some(bound)) => bound.to_uint(), @@ -1980,6 +1981,7 @@ impl + PartialOrd + Clone + ToPrimitive> Iterator for Range { }, None => match self.state.to_u64() { Some(a) => { + let a = a; let sz = self.stop.to_u64().map(|b| b.checked_sub(&a)); match sz { Some(Some(bound)) => bound.to_uint(), diff --git a/src/libregex_macros/lib.rs b/src/libregex_macros/lib.rs index 8aa9a2fc8fb94..10595db7ab888 100644 --- a/src/libregex_macros/lib.rs +++ b/src/libregex_macros/lib.rs @@ -426,7 +426,7 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str, _ => quote_expr!(self.cx, nlist.add($pc, &*groups)), }; self.arm_inst(pc, body) - }).collect::>(); + }).collect::>>(); self.match_insts(arms) } @@ -516,7 +516,7 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str, _ => self.empty_block(), }; self.arm_inst(pc, body) - }).collect::>(); + }).collect::>>(); self.match_insts(arms) } @@ -535,7 +535,7 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str, let pat = self.cx.pat(self.sp, ast::PatRange(quote_expr!(self.cx, $start), quote_expr!(self.cx, $end))); self.cx.arm(self.sp, vec!(pat), expr_true) - }).collect::>(); + }).collect::>>(); arms.push(self.wild_arm_expr(quote_expr!(self.cx, false))); @@ -570,7 +570,7 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str, // A wild-card arm is automatically added that executes a no-op. It will // never be used, but is added to satisfy the compiler complaining about // non-exhaustive patterns. - fn match_insts(&self, mut arms: Vec) -> Gc { + fn match_insts(&self, mut arms: Vec>) -> Gc { arms.push(self.wild_arm_expr(self.empty_block())); self.cx.expr_match(self.sp, quote_expr!(self.cx, pc), arms) } @@ -581,15 +581,15 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str, // Creates a match arm for the instruction at `pc` with the expression // `body`. - fn arm_inst(&self, pc: uint, body: Gc) -> ast::Arm { + fn arm_inst(&self, pc: uint, body: Gc) -> Gc { let pc_pat = self.cx.pat_lit(self.sp, quote_expr!(self.cx, $pc)); self.cx.arm(self.sp, vec!(pc_pat), body) } // Creates a wild-card match arm with the expression `body`. - fn wild_arm_expr(&self, body: Gc) -> ast::Arm { - ast::Arm { + fn wild_arm_expr(&self, body: Gc) -> Gc { + box(GC) ast::Arm { attrs: vec!(), pats: vec!(box(GC) ast::Pat{ id: ast::DUMMY_NODE_ID, @@ -598,6 +598,8 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str, }), guard: None, body: body, + id: ast::DUMMY_NODE_ID, + span: self.sp, } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 03dfcec18dbdb..6ba85c81365b2 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -37,6 +37,7 @@ This API is completely unstable and subject to change. #![feature(import_shadowing)] extern crate arena; +extern crate collections; extern crate debug; extern crate flate; extern crate getopts; @@ -94,6 +95,7 @@ pub mod middle { pub mod kind; pub mod lang_items; pub mod liveness; + pub mod loop_analysis; pub mod mem_categorization; pub mod pat_util; pub mod privacy; @@ -102,6 +104,7 @@ pub mod middle { pub mod resolve; pub mod resolve_lifetime; pub mod save; + pub mod seme_region; pub mod stability; pub mod subst; pub mod trans; diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 1386e23b77dfc..86b1e372640a5 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -198,7 +198,7 @@ pub fn write_type(ecx: &EncodeContext, pub fn write_region(ecx: &EncodeContext, rbml_w: &mut Encoder, - r: ty::Region) { + r: &ty::Region) { let ty_str_ctxt = &tyencode::ctxt { diag: ecx.diag, ds: def_to_string, @@ -231,9 +231,7 @@ fn encode_type(ecx: &EncodeContext, rbml_w.end_tag(); } -fn encode_region(ecx: &EncodeContext, - rbml_w: &mut Encoder, - r: ty::Region) { +fn encode_region(ecx: &EncodeContext, rbml_w: &mut Encoder, r: &ty::Region) { rbml_w.start_tag(tag_items_data_region); write_region(ecx, rbml_w, r); rbml_w.end_tag(); @@ -822,7 +820,7 @@ fn encode_generics(rbml_w: &mut Encoder, rbml_w.wr_tagged_u64(tag_region_param_def_index, param.index as u64); - for &bound_region in param.bounds.iter() { + for bound_region in param.bounds.iter() { encode_region(ecx, rbml_w, bound_region); } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index c18d2a7ebf404..461577f1807ce 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -16,6 +16,7 @@ #![allow(non_camel_case_types)] +use middle::seme_region::SemeRegion; use middle::subst; use middle::subst::VecPerParamSpace; use middle::ty; @@ -310,9 +311,13 @@ fn parse_region(st: &mut PState, conv: conv_did) -> ty::Region { bound_region: br}) } 's' => { - let id = parse_uint(st) as ast::NodeId; - assert_eq!(next(st), '|'); - ty::ReScope(id) + assert_eq!(next(st), '['); + let entry = parse_uint(st) as ast::NodeId; + let mut exits = Vec::new(); + while next(st) == '|' { + exits.push(parse_uint(st) as ast::NodeId); + } + ty::ReSemeRegion(SemeRegion::new(entry, exits)) } 't' => { ty::ReStatic diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 09be5094dc578..d89c1c030e30f 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -122,13 +122,13 @@ fn enc_region_substs(w: &mut SeekableMemWriter, cx: &ctxt, substs: &subst::Regio subst::NonerasedRegions(ref regions) => { mywrite!(w, "n"); enc_vec_per_param_space(w, cx, regions, - |w, cx, &r| enc_region(w, cx, r)); + |w, cx, r| enc_region(w, cx, r)); } } } -pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) { - match r { +pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: &ty::Region) { + match *r { ty::ReLateBound(id, br) => { mywrite!(w, "b[{}|", id); enc_bound_region(w, cx, br); @@ -146,8 +146,12 @@ pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) { enc_bound_region(w, cx, fr.bound_region); mywrite!(w, "]"); } - ty::ReScope(nid) => { - mywrite!(w, "s{}|", nid); + ty::ReSemeRegion(ref seme_region) => { + mywrite!(w, "s[{}", seme_region.entry); + for exit in seme_region.exits.iter() { + mywrite!(w, "|{}", *exit); + } + mywrite!(w, "]"); } ty::ReStatic => { mywrite!(w, "t"); @@ -183,10 +187,12 @@ pub fn enc_trait_ref(w: &mut SeekableMemWriter, cx: &ctxt, s: &ty::TraitRef) { enc_substs(w, cx, &s.substs); } -pub fn enc_trait_store(w: &mut SeekableMemWriter, cx: &ctxt, s: ty::TraitStore) { - match s { +pub fn enc_trait_store(w: &mut SeekableMemWriter, + cx: &ctxt, + s: &ty::TraitStore) { + match *s { ty::UniqTraitStore => mywrite!(w, "~"), - ty::RegionTraitStore(re, m) => { + ty::RegionTraitStore(ref re, m) => { mywrite!(w, "&"); enc_region(w, cx, re); enc_mutability(w, m); @@ -247,7 +253,7 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) { ty::ty_box(typ) => { mywrite!(w, "@"); enc_ty(w, cx, typ); } ty::ty_uniq(typ) => { mywrite!(w, "~"); enc_ty(w, cx, typ); } ty::ty_ptr(mt) => { mywrite!(w, "*"); enc_mt(w, cx, mt); } - ty::ty_rptr(r, mt) => { + ty::ty_rptr(ref r, mt) => { mywrite!(w, "&"); enc_region(w, cx, r); enc_mt(w, cx, mt); @@ -283,7 +289,7 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) { enc_substs(w, cx, substs); mywrite!(w, "]"); } - ty::ty_unboxed_closure(def, region) => { + ty::ty_unboxed_closure(def, ref region) => { mywrite!(w, "k{}", (cx.ds)(def)); enc_region(w, cx, region); } @@ -325,7 +331,7 @@ pub fn enc_bare_fn_ty(w: &mut SeekableMemWriter, cx: &ctxt, ft: &ty::BareFnTy) { pub fn enc_closure_ty(w: &mut SeekableMemWriter, cx: &ctxt, ft: &ty::ClosureTy) { enc_fn_style(w, ft.fn_style); enc_onceness(w, ft.onceness); - enc_trait_store(w, cx, ft.store); + enc_trait_store(w, cx, &ft.store); enc_existential_bounds(w, cx, &ft.bounds); enc_fn_sig(w, cx, &ft.sig); enc_abi(w, ft.abi); @@ -358,15 +364,17 @@ pub fn enc_builtin_bounds(w: &mut SeekableMemWriter, _cx: &ctxt, bs: &ty::Builti mywrite!(w, "."); } -pub fn enc_existential_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ExistentialBounds) { - enc_region(w, cx, bs.region_bound); +pub fn enc_existential_bounds(w: &mut SeekableMemWriter, + cx: &ctxt, + bs: &ty::ExistentialBounds) { + enc_region(w, cx, &bs.region_bound); enc_builtin_bounds(w, cx, &bs.builtin_bounds); } pub fn enc_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ParamBounds) { enc_builtin_bounds(w, cx, &bs.builtin_bounds); - for &r in bs.opt_region_bound.iter() { + for r in bs.opt_region_bound.iter() { mywrite!(w, "R"); enc_region(w, cx, r); } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index ee964c729fca3..32bf50e9de783 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -25,6 +25,7 @@ use metadata::tydecode; use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter}; use metadata::tydecode::{RegionParameter}; use metadata::tyencode; +use middle::seme_region::SemeRegion; use middle::subst; use middle::subst::VecPerParamSpace; use middle::typeck::{MethodCall, MethodCallee, MethodOrigin}; @@ -506,12 +507,10 @@ impl tr for ty::Region { ty::ReEarlyBound(id, space, index, ident) => { ty::ReEarlyBound(xcx.tr_id(id), space, index, ident) } - ty::ReScope(id) => { - ty::ReScope(xcx.tr_id(id)) - } - ty::ReEmpty | ty::ReStatic | ty::ReInfer(..) => { - *self + ty::ReSemeRegion(ref seme_region) => { + ty::ReSemeRegion(seme_region.tr(xcx)) } + ty::ReEmpty | ty::ReStatic | ty::ReInfer(..) => (*self).clone(), ty::ReFree(ref fr) => { ty::ReFree(ty::FreeRegion {scope_id: xcx.tr_id(fr.scope_id), bound_region: fr.bound_region.tr(xcx)}) @@ -520,6 +519,15 @@ impl tr for ty::Region { } } +impl tr for SemeRegion { + fn tr(&self, xcx: &ExtendedDecodeContext) -> SemeRegion { + SemeRegion { + entry: xcx.tr_id(self.entry), + exits: self.exits.iter().map(|id| xcx.tr_id(*id)).collect(), + } + } +} + impl tr for ty::BoundRegion { fn tr(&self, xcx: &ExtendedDecodeContext) -> ty::BoundRegion { match *self { @@ -534,7 +542,7 @@ impl tr for ty::BoundRegion { impl tr for ty::TraitStore { fn tr(&self, xcx: &ExtendedDecodeContext) -> ty::TraitStore { match *self { - ty::RegionTraitStore(r, m) => { + ty::RegionTraitStore(ref r, m) => { ty::RegionTraitStore(r.tr(xcx), m) } ty::UniqTraitStore => ty::UniqTraitStore @@ -1026,7 +1034,7 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { self.emit_enum("AutoAdjustment", |this| { match *adj { - ty::AutoAddEnv(store) => { + ty::AutoAddEnv(ref store) => { this.emit_enum_variant("AutoAddEnv", 0, 1, |this| { this.emit_enum_variant_arg(0, |this| store.encode(this)) }) @@ -1047,7 +1055,7 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { self.emit_enum("AutoRef", |this| { match autoref { - &ty::AutoPtr(r, m, None) => { + &ty::AutoPtr(ref r, m, None) => { this.emit_enum_variant("AutoPtr", 0, 3, |this| { this.emit_enum_variant_arg(0, |this| r.encode(this)); this.emit_enum_variant_arg(1, |this| m.encode(this)); @@ -1055,7 +1063,7 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { |this| this.emit_option(|this| this.emit_option_none())) }) } - &ty::AutoPtr(r, m, Some(box ref a)) => { + &ty::AutoPtr(ref r, m, Some(box ref a)) => { this.emit_enum_variant("AutoPtr", 0, 3, |this| { this.emit_enum_variant_arg(0, |this| r.encode(this)); this.emit_enum_variant_arg(1, |this| m.encode(this)); diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index a69fe6958e175..cb296d109bcab 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -114,10 +114,9 @@ impl<'a> euv::Delegate for CheckLoanCtxt<'a> { borrow_id: ast::NodeId, borrow_span: Span, cmt: mc::cmt, - loan_region: ty::Region, + loan_region: &ty::Region, bk: ty::BorrowKind, - loan_cause: euv::LoanCause) - { + loan_cause: euv::LoanCause) { debug!("borrow(borrow_id={}, cmt={}, loan_region={}, \ bk={}, loan_cause={:?})", borrow_id, cmt.repr(self.tcx()), loan_region, @@ -195,7 +194,7 @@ pub fn check_loans(bccx: &BorrowckCtxt, }; { - let mut euv = euv::ExprUseVisitor::new(&mut clcx, bccx.tcx); + let mut euv = euv::ExprUseVisitor::new(&mut clcx, bccx); euv.walk_fn(decl, body); } } @@ -238,11 +237,14 @@ impl<'a> CheckLoanCtxt<'a> { let tcx = self.tcx(); self.each_issued_loan(scope_id, |loan| { - if tcx.region_maps.is_subscope_of(scope_id, loan.kill_scope) { - op(loan) - } else { - true + let mut result = true; + for kill_scope in loan.kill_scopes.iter() { + if tcx.region_maps.is_subscope_of(scope_id, *kill_scope) { + result = op(loan); + break + } } + result }) } @@ -369,8 +371,6 @@ impl<'a> CheckLoanCtxt<'a> { new_loan.repr(self.tcx())); // Should only be called for loans that are in scope at the same time. - assert!(self.tcx().region_maps.scopes_intersect(old_loan.kill_scope, - new_loan.kill_scope)); self.report_error_if_loan_conflicts_with_restriction( old_loan, new_loan, old_loan, new_loan) && @@ -504,9 +504,11 @@ impl<'a> CheckLoanCtxt<'a> { old_loan.span, format!("{}; {}", borrow_summary, rule_summary).as_slice()); - let old_loan_span = self.tcx().map.span(old_loan.kill_scope); - self.bccx.span_end_note(old_loan_span, - "previous borrow ends here"); + for kill_scope in old_loan.kill_scopes.iter() { + let old_loan_span = self.tcx().map.span(*kill_scope); + self.bccx.span_end_note(old_loan_span, + "previous borrow ends here"); + } return false; } diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index c6fbbed1f8a16..5f223719c3c72 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -16,6 +16,7 @@ use middle::borrowck::*; use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; +use middle::seme_region::SemeRegion; use middle::ty; use util::ppaux::Repr; use syntax::ast; @@ -28,17 +29,19 @@ pub fn guarantee_lifetime(bccx: &BorrowckCtxt, span: Span, cause: euv::LoanCause, cmt: mc::cmt, - loan_region: ty::Region, + loan_region: &ty::Region, _: ty::BorrowKind) -> Result<(),()> { debug!("guarantee_lifetime(cmt={}, loan_region={})", cmt.repr(bccx.tcx), loan_region.repr(bccx.tcx)); - let ctxt = GuaranteeLifetimeContext {bccx: bccx, - item_scope_id: item_scope_id, - span: span, - cause: cause, - loan_region: loan_region, - cmt_original: cmt.clone()}; + let ctxt = GuaranteeLifetimeContext { + bccx: bccx, + item_scope_id: item_scope_id, + span: span, + cause: cause, + loan_region: loan_region, + cmt_original: cmt.clone() + }; ctxt.check(&cmt, None) } @@ -53,12 +56,11 @@ struct GuaranteeLifetimeContext<'a> { span: Span, cause: euv::LoanCause, - loan_region: ty::Region, + loan_region: &'a ty::Region, cmt_original: mc::cmt } impl<'a> GuaranteeLifetimeContext<'a> { - fn check(&self, cmt: &mc::cmt, discr_scope: Option) -> R { //! Main routine. Walks down `cmt` until we find the "guarantor". debug!("guarantee_lifetime.check(cmt={}, loan_region={})", @@ -74,7 +76,7 @@ impl<'a> GuaranteeLifetimeContext<'a> { mc::cat_deref(_, _, mc::BorrowedPtr(..)) | // L-Deref-Borrowed mc::cat_deref(_, _, mc::Implicit(..)) | mc::cat_deref(_, _, mc::UnsafePtr(..)) => { - self.check_scope(self.scope(cmt)) + self.check_scope(&self.scope(cmt)) } mc::cat_static_item => { @@ -146,11 +148,13 @@ impl<'a> GuaranteeLifetimeContext<'a> { } } - fn check_scope(&self, max_scope: ty::Region) -> R { + fn check_scope(&self, max_scope: &ty::Region) -> R { //! Reports an error if `loan_region` is larger than `valid_scope` - if !self.bccx.is_subregion_of(self.loan_region, max_scope) { - Err(self.report_error(err_out_of_scope(max_scope, self.loan_region))) + if !self.is_subregion_of(self.loan_region, max_scope) { + Err(self.report_error(err_out_of_scope( + (*max_scope).clone(), + (*self.loan_region).clone()))) } else { Ok(()) } @@ -164,27 +168,31 @@ impl<'a> GuaranteeLifetimeContext<'a> { // See the SCOPE(LV) function in doc.rs match cmt.cat { - mc::cat_rvalue(temp_scope) => { - temp_scope - } + mc::cat_rvalue(ref temp_scope) => (*temp_scope).clone(), mc::cat_upvar(..) | mc::cat_copied_upvar(_) => { - ty::ReScope(self.item_scope_id) + ty::ReSemeRegion(SemeRegion::from_scope( + self.bccx.tcx, + self.bccx.loop_analysis(), + self.item_scope_id)) } mc::cat_static_item => { ty::ReStatic } mc::cat_local(local_id) | mc::cat_arg(local_id) => { - ty::ReScope(self.bccx.tcx.region_maps.var_scope(local_id)) - } - mc::cat_deref(_, _, mc::UnsafePtr(..)) => { - ty::ReStatic - } - mc::cat_deref(_, _, mc::BorrowedPtr(_, r)) | - mc::cat_deref(_, _, mc::Implicit(_, r)) => { - r + let var_scope = self.bccx.tcx.region_maps.var_scope(local_id); + ty::ReSemeRegion(SemeRegion::from_scope( + self.bccx.tcx, + self.bccx.loop_analysis(), + var_scope)) } + + mc::cat_deref(_, _, mc::UnsafePtr(..)) => ty::ReStatic, + + mc::cat_deref(_, _, mc::BorrowedPtr(_, ref r)) | + mc::cat_deref(_, _, mc::Implicit(_, ref r)) => (*r).clone(), + mc::cat_downcast(ref cmt) | mc::cat_deref(ref cmt, _, mc::OwnedPtr) | mc::cat_deref(ref cmt, _, mc::GcPtr) | @@ -196,9 +204,16 @@ impl<'a> GuaranteeLifetimeContext<'a> { } fn report_error(&self, code: bckerr_code) { - self.bccx.report(BckError { cmt: self.cmt_original.clone(), - span: self.span, - cause: self.cause, - code: code }); + self.bccx.report(BckError { + cmt: self.cmt_original.clone(), + span: self.span, + cause: self.cause, + code: code, + }); + } + + fn is_subregion_of(&self, r_sub: &ty::Region, r_sup: &ty::Region) + -> bool { + self.bccx.tcx.region_maps.is_subregion_of(self.bccx.tcx, r_sub, r_sup) } } diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 82e1748465f61..0680d0f22c48c 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -20,6 +20,7 @@ use middle::borrowck::*; use middle::borrowck::move_data::MoveData; use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; +use middle::seme_region::SemeRegion; use middle::ty; use util::ppaux::{Repr}; @@ -37,8 +38,7 @@ mod move_error; pub fn gather_loans_in_fn(bccx: &BorrowckCtxt, decl: &ast::FnDecl, body: &ast::Block) - -> (Vec, move_data::MoveData) -{ + -> (Vec, move_data::MoveData) { let mut glcx = GatherLoanCtxt { bccx: bccx, all_loans: Vec::new(), @@ -48,7 +48,7 @@ pub fn gather_loans_in_fn(bccx: &BorrowckCtxt, }; { - let mut euv = euv::ExprUseVisitor::new(&mut glcx, bccx.tcx); + let mut euv = euv::ExprUseVisitor::new(&mut glcx, bccx); euv.walk_fn(decl, body); } @@ -107,10 +107,9 @@ impl<'a> euv::Delegate for GatherLoanCtxt<'a> { borrow_id: ast::NodeId, borrow_span: Span, cmt: mc::cmt, - loan_region: ty::Region, + loan_region: &ty::Region, bk: ty::BorrowKind, - loan_cause: euv::LoanCause) - { + loan_cause: euv::LoanCause) { debug!("borrow(borrow_id={}, cmt={}, loan_region={}, \ bk={}, loan_cause={:?})", borrow_id, cmt.repr(self.tcx()), loan_region, @@ -212,7 +211,7 @@ impl<'a> GatherLoanCtxt<'a> { borrow_span: Span, cmt: mc::cmt, req_kind: ty::BorrowKind, - loan_region: ty::Region, + loan_region: &ty::Region, cause: euv::LoanCause) { /*! * Guarantees that `addr_of(cmt)` will be valid for the duration of @@ -231,35 +230,47 @@ impl<'a> GatherLoanCtxt<'a> { // a loan for the empty region can never be dereferenced, so // it is always safe - if loan_region == ty::ReEmpty { + if *loan_region == ty::ReEmpty { return; } // Check that the lifetime of the borrow does not exceed // the lifetime of the data being borrowed. - if lifetime::guarantee_lifetime(self.bccx, self.item_ub, - borrow_span, cause, cmt.clone(), loan_region, + if lifetime::guarantee_lifetime(self.bccx, + self.item_ub, + borrow_span, + cause, + cmt.clone(), + loan_region, req_kind).is_err() { return; // reported an error, no sense in reporting more. } // Check that we don't allow mutable borrows of non-mutable data. - if check_mutability(self.bccx, borrow_span, cause, - cmt.clone(), req_kind).is_err() { + if check_mutability(self.bccx, + borrow_span, + cause, + cmt.clone(), + req_kind).is_err() { return; // reported an error, no sense in reporting more. } // Check that we don't allow mutable borrows of aliasable data. - if check_aliasability(self.bccx, borrow_span, cause, - cmt.clone(), req_kind).is_err() { + if check_aliasability(self.bccx, + borrow_span, + cause, + cmt.clone(), + req_kind).is_err() { return; // reported an error, no sense in reporting more. } // Compute the restrictions that are required to enforce the // loan is safe. - let restr = restrictions::compute_restrictions( - self.bccx, borrow_span, cause, - cmt.clone(), loan_region); + let restr = restrictions::compute_restrictions(self.bccx, + borrow_span, + cause, + cmt.clone(), + loan_region); debug!("guarantee_valid(): restrictions={:?}", restr); @@ -271,9 +282,13 @@ impl<'a> GatherLoanCtxt<'a> { } restrictions::SafeIf(loan_path, restricted_paths) => { - let loan_scope = match loan_region { - ty::ReScope(id) => id, - ty::ReFree(ref fr) => fr.scope_id, + let loan_region = match *loan_region { + ty::ReSemeRegion(ref region) => (*region).clone(), + ty::ReFree(ref fr) => { + SemeRegion::from_scope(self.bccx.tcx, + self.bccx.loop_analysis(), + fr.scope_id) + } ty::ReStatic => { // If we get here, an error must have been @@ -297,13 +312,15 @@ impl<'a> GatherLoanCtxt<'a> { loan_region).as_slice()); } }; - debug!("loan_scope = {:?}", loan_scope); + debug!("loan_region = {}", loan_region); - let gen_scope = self.compute_gen_scope(borrow_id, loan_scope); + let gen_scope = self.compute_gen_scope(borrow_id, + &loan_region); debug!("gen_scope = {:?}", gen_scope); - let kill_scope = self.compute_kill_scope(loan_scope, &*loan_path); - debug!("kill_scope = {:?}", kill_scope); + let kill_scopes = self.compute_kill_scopes(&loan_region, + &*loan_path); + debug!("kill_scopes = {}", kill_scopes); if req_kind == ty::MutBorrow { self.mark_loan_path_as_mutated(&*loan_path); @@ -314,7 +331,7 @@ impl<'a> GatherLoanCtxt<'a> { loan_path: loan_path, kind: req_kind, gen_scope: gen_scope, - kill_scope: kill_scope, + kill_scopes: kill_scopes, span: borrow_span, restricted_paths: restricted_paths, cause: cause, @@ -380,10 +397,12 @@ impl<'a> GatherLoanCtxt<'a> { ty::MutBorrow => { // Only mutable data can be lent as mutable. if !cmt.mutbl.is_mutable() { - Err(bccx.report(BckError { span: borrow_span, - cause: cause, - cmt: cmt, - code: err_mutbl })) + Err(bccx.report(BckError { + span: borrow_span, + cause: cause, + cmt: cmt, + code: err_mutbl, + })) } else { Ok(()) } @@ -413,13 +432,14 @@ impl<'a> GatherLoanCtxt<'a> { pub fn compute_gen_scope(&self, borrow_id: ast::NodeId, - loan_scope: ast::NodeId) + loan_region: &SemeRegion) -> ast::NodeId { //! Determine when to introduce the loan. Typically the loan //! is introduced at the point of the borrow, but in some cases, //! notably method arguments, the loan may be introduced only //! later, once it comes into scope. + let loan_scope = loan_region.entry; if self.bccx.tcx.region_maps.is_subscope_of(borrow_id, loan_scope) { borrow_id } else { @@ -427,8 +447,10 @@ impl<'a> GatherLoanCtxt<'a> { } } - pub fn compute_kill_scope(&self, loan_scope: ast::NodeId, lp: &LoanPath) - -> ast::NodeId { + pub fn compute_kill_scopes(&self, + loan_region: &SemeRegion, + lp: &LoanPath) + -> Vec { //! Determine when the loan restrictions go out of scope. //! This is either when the lifetime expires or when the //! local variable which roots the loan-path goes out of scope, @@ -449,12 +471,21 @@ impl<'a> GatherLoanCtxt<'a> { //! do not require restrictions and hence do not cause a loan. let lexical_scope = lp.kill_scope(self.bccx.tcx); + let loan_scopes = loan_region.exits.as_slice(); + + let mut loan_outlives_lexical_scope = true; let rm = &self.bccx.tcx.region_maps; - if rm.is_subscope_of(lexical_scope, loan_scope) { - lexical_scope + for loan_scope in loan_scopes.iter() { + if !rm.is_subscope_of(lexical_scope, *loan_scope) { + loan_outlives_lexical_scope = false; + break + } + } + + if loan_outlives_lexical_scope { + vec![lexical_scope] } else { - assert!(self.bccx.tcx.region_maps.is_subscope_of(loan_scope, lexical_scope)); - loan_scope + loan_scopes.iter().map(|x| (*x).clone()).collect::>() } } diff --git a/src/librustc/middle/borrowck/gather_loans/restrictions.rs b/src/librustc/middle/borrowck/gather_loans/restrictions.rs index a686084a4a2bc..458fcb5c3f9bf 100644 --- a/src/librustc/middle/borrowck/gather_loans/restrictions.rs +++ b/src/librustc/middle/borrowck/gather_loans/restrictions.rs @@ -30,7 +30,8 @@ pub fn compute_restrictions(bccx: &BorrowckCtxt, span: Span, cause: euv::LoanCause, cmt: mc::cmt, - loan_region: ty::Region) -> RestrictionResult { + loan_region: &ty::Region) + -> RestrictionResult { let ctxt = RestrictionsContext { bccx: bccx, span: span, @@ -47,13 +48,12 @@ pub fn compute_restrictions(bccx: &BorrowckCtxt, struct RestrictionsContext<'a> { bccx: &'a BorrowckCtxt<'a>, span: Span, - loan_region: ty::Region, + loan_region: &'a ty::Region, cause: euv::LoanCause, } impl<'a> RestrictionsContext<'a> { - fn restrict(&self, - cmt: mc::cmt) -> RestrictionResult { + fn restrict(&self, cmt: mc::cmt) -> RestrictionResult { debug!("restrict(cmt={})", cmt.repr(self.bccx.tcx)); match cmt.cat.clone() { @@ -125,14 +125,15 @@ impl<'a> RestrictionsContext<'a> { mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::ImmBorrow, lt)) | mc::cat_deref(cmt_base, _, mc::Implicit(ty::ImmBorrow, lt)) => { // R-Deref-Imm-Borrowed - if !self.bccx.is_subregion_of(self.loan_region, lt) { - self.bccx.report( - BckError { - span: self.span, - cause: self.cause, - cmt: cmt_base, - code: err_borrowed_pointer_too_short( - self.loan_region, lt)}); + if !self.is_subregion_of(self.loan_region, <) { + self.bccx.report(BckError { + span: self.span, + cause: self.cause, + cmt: cmt_base, + code: err_borrowed_pointer_too_short( + self.loan_region.clone(), + lt), + }); return Safe; } Safe @@ -140,24 +141,25 @@ impl<'a> RestrictionsContext<'a> { mc::cat_deref(cmt_base, _, pk) => { match pk { - mc::BorrowedPtr(ty::MutBorrow, lt) | - mc::BorrowedPtr(ty::UniqueImmBorrow, lt) | - mc::Implicit(ty::MutBorrow, lt) | - mc::Implicit(ty::UniqueImmBorrow, lt) => { + mc::BorrowedPtr(ty::MutBorrow, ref lt) | + mc::BorrowedPtr(ty::UniqueImmBorrow, ref lt) | + mc::Implicit(ty::MutBorrow, ref lt) | + mc::Implicit(ty::UniqueImmBorrow, ref lt) => { // R-Deref-Mut-Borrowed - if !self.bccx.is_subregion_of(self.loan_region, lt) { - self.bccx.report( - BckError { - span: self.span, - cause: self.cause, - cmt: cmt_base, - code: err_borrowed_pointer_too_short( - self.loan_region, lt)}); + if !self.is_subregion_of(self.loan_region, lt) { + self.bccx.report(BckError { + span: self.span, + cause: self.cause, + cmt: cmt_base, + code: err_borrowed_pointer_too_short( + self.loan_region.clone(), + (*lt).clone()) + }); return Safe; } let result = self.restrict(cmt_base); - self.extend(result, cmt.mutbl, LpDeref(pk)) + self.extend(result, cmt.mutbl, LpDeref(pk.clone())) } mc::UnsafePtr(..) => { // We are very trusting when working with unsafe @@ -191,4 +193,9 @@ impl<'a> RestrictionsContext<'a> { } } } + + fn is_subregion_of(&self, r_sub: &ty::Region, r_sup: &ty::Region) + -> bool { + self.bccx.tcx.region_maps.is_subregion_of(self.bccx.tcx, r_sub, r_sup) + } } diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 230786924d7c4..acaea9013419e 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -18,13 +18,18 @@ use middle::dataflow::BitwiseOperator; use middle::dataflow::DataFlowOperator; use middle::def; use middle::expr_use_visitor as euv; +use middle::freevars; +use middle::loop_analysis::{LoopAnalysis, LoopAnalyzer}; use middle::mem_categorization as mc; use middle::ty; +use middle::typeck; +use util::nodemap::{DefIdMap, NodeMap}; use util::ppaux::{note_and_explain_region, Repr, UserString}; -use std::cell::{Cell}; -use std::rc::Rc; +use std::cell::{Cell, RefCell}; use std::gc::{Gc, GC}; +use std::mem; +use std::rc::Rc; use std::string::String; use syntax::ast; use syntax::ast_map; @@ -75,6 +80,7 @@ pub fn check_crate(tcx: &ty::ctxt, krate: &ast::Crate) { let mut bccx = BorrowckCtxt { tcx: tcx, + loop_analysis: None, stats: box(GC) BorrowStats { loaned_paths_same: Cell::new(0), loaned_paths_imm: Cell::new(0), @@ -133,6 +139,18 @@ fn borrowck_fn(this: &mut BorrowckCtxt, sp: Span, id: ast::NodeId) { debug!("borrowck_fn(id={})", id); + + // Perform loop analysis... + let mut old_loop_analysis = None; + match *fk { + visit::FkItemFn(..) | visit::FkMethod(..) => { + old_loop_analysis = mem::replace(&mut this.loop_analysis, None); + this.loop_analysis = + Some(LoopAnalyzer::new(this.tcx).analyze_block(body)); + } + visit::FkFnBlock(..) => {} + } + let cfg = cfg::CFG::new(this.tcx, body); let AnalysisData { all_loans, loans: loan_dfcx, @@ -143,6 +161,14 @@ fn borrowck_fn(this: &mut BorrowckCtxt, all_loans.as_slice(), decl, body); visit::walk_fn(this, fk, decl, body, sp, ()); + + // Restore the old loop analysis. + match *fk { + visit::FkItemFn(..) | visit::FkMethod(..) => { + this.loop_analysis = old_loop_analysis + } + visit::FkFnBlock(..) => {} + } } fn build_borrowck_dataflow_data<'a>(this: &mut BorrowckCtxt<'a>, @@ -167,7 +193,10 @@ fn build_borrowck_dataflow_data<'a>(this: &mut BorrowckCtxt<'a>, all_loans.len()); for (loan_idx, loan) in all_loans.iter().enumerate() { loan_dfcx.add_gen(loan.gen_scope, loan_idx); - loan_dfcx.add_kill(loan.kill_scope, loan_idx); + for kill_scope in loan.kill_scopes.iter() { + debug!("add_kill({})", this.tcx.map.node_to_string(*kill_scope)); + loan_dfcx.add_kill(*kill_scope, loan_idx); + } } loan_dfcx.add_kills_from_flow_exits(cfg); loan_dfcx.propagate(cfg, body); @@ -204,8 +233,11 @@ pub fn build_borrowck_dataflow_data_for_fn<'a>( tcx: &'a ty::ctxt, input: FnPartsWithCFG<'a>) -> (BorrowckCtxt<'a>, AnalysisData<'a>) { + let p = input.fn_parts; + let mut bccx = BorrowckCtxt { tcx: tcx, + loop_analysis: Some(LoopAnalyzer::new(tcx).analyze_block(&*p.body)), stats: box(GC) BorrowStats { loaned_paths_same: Cell::new(0), loaned_paths_imm: Cell::new(0), @@ -214,8 +246,6 @@ pub fn build_borrowck_dataflow_data_for_fn<'a>( } }; - let p = input.fn_parts; - let dataflow_data = build_borrowck_dataflow_data(&mut bccx, &p.kind, &*p.decl, @@ -233,10 +263,65 @@ pub fn build_borrowck_dataflow_data_for_fn<'a>( pub struct BorrowckCtxt<'a> { tcx: &'a ty::ctxt, + loop_analysis: Option, + // Statistics: stats: Gc, } +impl<'a> mc::Typer for BorrowckCtxt<'a> { + fn tcx<'a>(&'a self) -> &'a ty::ctxt { + self.tcx + } + + fn node_ty(&self, id: ast::NodeId) -> mc::McResult { + Ok(ty::node_id_to_type(self.tcx, id)) + } + + fn node_method_ty(&self, method_call: typeck::MethodCall) -> Option { + self.tcx + .method_map + .borrow() + .find(&method_call) + .map(|method| method.ty) + } + + fn adjustments<'a>(&'a self) -> &'a RefCell> { + &self.tcx.adjustments + } + + fn is_method_call(&self, id: ast::NodeId) -> bool { + self.tcx + .method_map + .borrow() + .contains_key(&typeck::MethodCall::expr(id)) + } + + fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option { + self.tcx.region_maps.temporary_scope(rvalue_id) + } + + fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow { + self.tcx.upvar_borrow_map.borrow().get_copy(&upvar_id) + } + + fn capture_mode(&self, closure_expr_id: ast::NodeId) + -> freevars::CaptureMode { + self.tcx.capture_modes.borrow().get_copy(&closure_expr_id) + } + + fn unboxed_closures(&self) -> &RefCell> { + &self.tcx.unboxed_closures + } + + fn loop_analysis(&self) -> Option<&LoopAnalysis> { + match self.loop_analysis { + None => None, + Some(ref loop_analysis) => Some(loop_analysis), + } + } +} + pub struct BorrowStats { loaned_paths_same: Cell, loaned_paths_imm: Cell, @@ -262,7 +347,7 @@ pub struct Loan { kind: ty::BorrowKind, restricted_paths: Vec>, gen_scope: ast::NodeId, - kill_scope: ast::NodeId, + kill_scopes: Vec, span: Span, cause: euv::LoanCause, } @@ -337,9 +422,9 @@ pub fn opt_loan_path(cmt: &mc::cmt) -> Option> { Some(Rc::new(LpUpvar(upvar_id))) } - mc::cat_deref(ref cmt_base, _, pk) => { + mc::cat_deref(ref cmt_base, _, ref pk) => { opt_loan_path(cmt_base).map(|lp| { - Rc::new(LpExtend(lp, cmt.mutbl, LpDeref(pk))) + Rc::new(LpExtend(lp, cmt.mutbl, LpDeref((*pk).clone()))) }) } @@ -391,9 +476,14 @@ pub enum MovedValueUseKind { // Misc impl<'a> BorrowckCtxt<'a> { - pub fn is_subregion_of(&self, r_sub: ty::Region, r_sup: ty::Region) - -> bool { - self.tcx.region_maps.is_subregion_of(r_sub, r_sup) + pub fn loop_analysis(&self) -> &LoopAnalysis { + match self.loop_analysis { + None => { + self.tcx.sess.bug("BorrowckCtxt::loop_analysis() called when \ + no loop analysis present") + } + Some(ref loop_analysis) => loop_analysis, + } } pub fn is_subscope_of(&self, r_sub: ast::NodeId, r_sup: ast::NodeId) @@ -491,9 +581,7 @@ impl<'a> BorrowckCtxt<'a> { } pub fn report(&self, err: BckError) { - self.span_err( - err.span, - self.bckerr_to_string(&err).as_slice()); + self.span_err(err.span, self.bckerr_to_string(&err).as_slice()); self.note_and_explain_bckerr(err); } @@ -745,18 +833,19 @@ impl<'a> BorrowckCtxt<'a> { } } - pub fn note_and_explain_bckerr(&self, err: BckError) { + fn note_and_explain_bckerr(&self, err: BckError) { let code = err.code; match code { err_mutbl(..) => { } - err_out_of_scope(super_scope, sub_scope) => { + err_out_of_scope(ref super_scope, ref sub_scope) => { note_and_explain_region( self.tcx, "reference must be valid for ", sub_scope, "..."); - let suggestion = if is_statement_scope(self.tcx, super_scope) { + let suggestion = if is_statement_scope(self.tcx, + super_scope) { "; consider using a `let` binding to increase its lifetime" } else { "" @@ -768,7 +857,7 @@ impl<'a> BorrowckCtxt<'a> { suggestion); } - err_borrowed_pointer_too_short(loan_scope, ptr_scope) => { + err_borrowed_pointer_too_short(ref loan_scope, ref ptr_scope) => { let descr = match opt_loan_path(&err.cmt) { Some(lp) => { format!("`{}`", self.loan_path_to_string(&*lp)) @@ -791,8 +880,8 @@ impl<'a> BorrowckCtxt<'a> { } pub fn append_loan_path_to_string(&self, - loan_path: &LoanPath, - out: &mut String) { + loan_path: &LoanPath, + out: &mut String) { match *loan_path { LpUpvar(ty::UpvarId{ var_id: id, closure_expr_id: _ }) | LpVar(id) => { @@ -853,10 +942,11 @@ impl<'a> BorrowckCtxt<'a> { } } -fn is_statement_scope(tcx: &ty::ctxt, region: ty::Region) -> bool { - match region { - ty::ReScope(node_id) => { - match tcx.map.find(node_id) { +fn is_statement_scope(tcx: &ty::ctxt, region: &ty::Region) -> bool { + match *region { + ty::ReSemeRegion(ref seme_region) => { + let scope_id = seme_region.lub_scope(tcx); + match tcx.map.find(scope_id) { Some(ast_map::NodeStmt(_)) => true, _ => false } @@ -881,12 +971,12 @@ impl DataFlowOperator for LoanDataFlowOperator { impl Repr for Loan { fn repr(&self, tcx: &ty::ctxt) -> String { - format!("Loan_{:?}({}, {:?}, {:?}-{:?}, {})", + format!("Loan_{:?}({}, {:?}, {:?}-[{}], {})", self.index, self.loan_path.repr(tcx), self.kind, self.gen_scope, - self.kill_scope, + self.kill_scopes, self.restricted_paths.repr(tcx)) } } diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 776067d49a218..2af98fe16af42 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -365,7 +365,8 @@ impl<'a> CFGBuilder<'a> { pats_exit); // 4 let body_exit = self.expr(arm.body.clone(), guard_exit); // 5 - self.add_contained_edge(body_exit, expr_exit); // 6 + let arm_exit = self.add_node(arm.id, [body_exit]); // 6 + self.add_contained_edge(arm_exit, expr_exit); // 6 } expr_exit } @@ -546,6 +547,7 @@ impl<'a> CFGBuilder<'a> { fn add_node(&mut self, id: ast::NodeId, preds: &[CFGIndex]) -> CFGIndex { assert!(!self.exit_map.contains_key(&id)); + debug!("add_node({})", id); let node = self.graph.add_node(CFGNodeData {id: id}); if id != ast::DUMMY_NODE_ID { assert!(!self.exit_map.contains_key(&id)); diff --git a/src/librustc/middle/cfg/graphviz.rs b/src/librustc/middle/cfg/graphviz.rs index 0cccae8b8c9cd..c8ee6b0c3beed 100644 --- a/src/librustc/middle/cfg/graphviz.rs +++ b/src/librustc/middle/cfg/graphviz.rs @@ -28,7 +28,7 @@ pub struct LabelledCFG<'a>{ pub name: String, } -fn replace_newline_with_backslash_l(s: String) -> String { +pub fn replace_newline_with_backslash_l(s: String) -> String { // Replacing newlines with \\l causes each line to be left-aligned, // improving presentation of (long) pretty-printed expressions. if s.as_slice().contains("\n") { diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index c234682471080..a1ae006b8fe89 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -167,7 +167,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) { pats: arm.pats.iter().map(|pat| { static_inliner.fold_pat(*pat) }).collect(), - ..arm.clone() + ..(**arm).clone() }) .collect::>(); @@ -982,7 +982,7 @@ impl<'a> Delegate for MutationChecker<'a> { _: NodeId, span: Span, _: cmt, - _: Region, + _: &Region, kind: BorrowKind, _: LoanCause) { match kind { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a7e49edbc8e4a..66272abdc043f 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -14,10 +14,11 @@ * `ExprUseVisitor` determines how expressions are being used. */ -use middle::mem_categorization as mc; use middle::def; use middle::freevars; +use middle::mem_categorization as mc; use middle::pat_util; +use middle::seme_region::SemeRegion; use middle::ty; use middle::typeck::{MethodCall, MethodObject, MethodOrigin, MethodParam}; use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure}; @@ -55,7 +56,7 @@ pub trait Delegate { borrow_id: ast::NodeId, borrow_span: Span, cmt: mc::cmt, - loan_region: ty::Region, + loan_region: &ty::Region, bk: ty::BorrowKind, loan_cause: LoanCause); @@ -215,12 +216,13 @@ macro_rules! return_if_err( ) impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { - pub fn new(delegate: &'d mut Delegate, - typer: &'t TYPER) + pub fn new(delegate: &'d mut Delegate, typer: &'t TYPER) -> ExprUseVisitor<'d,'t,TYPER> { - ExprUseVisitor { typer: typer, - mc: mc::MemCategorizationContext::new(typer), - delegate: delegate } + ExprUseVisitor { + typer: typer, + mc: mc::MemCategorizationContext::new(typer), + delegate: delegate, + } } pub fn walk_fn(&mut self, @@ -236,11 +238,19 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { for arg in decl.inputs.iter() { let arg_ty = return_if_err!(self.typer.node_ty(arg.pat.id)); - let arg_cmt = self.mc.cat_rvalue( - arg.id, - arg.pat.span, - ty::ReScope(body.id), // Args live only as long as the fn body. - arg_ty); + // Args live only as long as the fn body. + let arg_region = match self.typer.loop_analysis() { + None => ty::ReStatic, + Some(loop_analysis) => { + ty::ReSemeRegion(SemeRegion::from_scope(self.typer.tcx(), + loop_analysis, + body.id)) + } + }; + let arg_cmt = self.mc.cat_rvalue(arg.id, + arg.pat.span, + arg_region, + arg_ty); self.walk_pat(arg_cmt, arg.pat.clone()); } @@ -283,7 +293,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { fn borrow_expr(&mut self, expr: &ast::Expr, - r: ty::Region, + r: &ty::Region, bk: ty::BorrowKind, cause: LoanCause) { debug!("borrow_expr(expr={}, r={}, bk={})", @@ -362,7 +372,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { self.walk_expr(&**discr); let discr_cmt = return_if_err!(self.mc.cat_expr(&**discr)); for arm in arms.iter() { - self.walk_arm(discr_cmt.clone(), arm); + self.walk_arm(discr_cmt.clone(), &**arm); } } @@ -377,7 +387,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { if !ty::type_is_bot(expr_ty) { let r = ty::ty_region(self.tcx(), expr.span, expr_ty); let bk = ty::BorrowKind::from_mutbl(m); - self.borrow_expr(&**base, r, bk, AddrOf); + self.borrow_expr(&**base, &r, bk, AddrOf); } else { self.walk_expr(&**base); } @@ -415,9 +425,18 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { // Fetch the type of the value that the iteration yields to // produce the pattern's categorized mutable type. let pattern_type = return_if_err!(self.typer.node_ty(pat.id)); + let pat_region = match self.typer.loop_analysis() { + None => ty::ReStatic, + Some(loop_analysis) => { + ty::ReSemeRegion( + SemeRegion::from_scope(self.typer.tcx(), + loop_analysis, + blk.id)) + } + }; let pat_cmt = self.mc.cat_rvalue(pat.id, pat.span, - ty::ReScope(blk.id), + pat_region, pattern_type); self.walk_pat(pat_cmt, pat.clone()); @@ -498,8 +517,20 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { ty::ty_closure(ref f) => { match f.onceness { ast::Many => { + let region = { + let tcx = self.tcx(); + match self.typer.loop_analysis() { + None => ty::ReStatic, + Some(loop_analysis) => { + ty::ReSemeRegion( + SemeRegion::from_scope(tcx, + loop_analysis, + call.id)) + } + } + }; self.borrow_expr(callee, - ty::ReScope(call.id), + ®ion, ty::UniqueImmBorrow, ClosureInvocation); } @@ -528,14 +559,38 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { }; match overloaded_call_type { FnMutOverloadedCall => { + let region = { + let tcx = self.tcx(); + match self.typer.loop_analysis() { + None => ty::ReStatic, + Some(loop_analysis) => { + ty::ReSemeRegion(SemeRegion::from_scope( + tcx, + loop_analysis, + call.id)) + } + } + }; self.borrow_expr(callee, - ty::ReScope(call.id), + ®ion, ty::MutBorrow, ClosureInvocation); } FnOverloadedCall => { + let region = { + let tcx = self.tcx(); + match self.typer.loop_analysis() { + None => ty::ReStatic, + Some(loop_analysis) => { + ty::ReSemeRegion(SemeRegion::from_scope( + tcx, + loop_analysis, + call.id)) + } + } + }; self.borrow_expr(callee, - ty::ReScope(call.id), + ®ion, ty::ImmBorrow, ClosureInvocation); } @@ -714,14 +769,18 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { let cmt = return_if_err!(self.mc.cat_expr_autoderefd(expr, i)); let self_ty = *ty::ty_fn_args(method_ty).get(0); let (m, r) = match ty::get(self_ty).sty { - ty::ty_rptr(r, ref m) => (m.mutbl, r), + ty::ty_rptr(ref r, ref m) => (m.mutbl, (*r).clone()), _ => self.tcx().sess.span_bug(expr.span, format!("bad overloaded deref type {}", method_ty.repr(self.tcx())).as_slice()) }; let bk = ty::BorrowKind::from_mutbl(m); - self.delegate.borrow(expr.id, expr.span, cmt, - r, bk, AutoRef); + self.delegate.borrow(expr.id, + expr.span, + cmt, + &r, + bk, + AutoRef); } } } @@ -754,7 +813,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { cmt_derefd.repr(self.tcx())); match *autoref { - ty::AutoPtr(r, m, _) => { + ty::AutoPtr(ref r, m, _) => { self.delegate.borrow(expr.id, expr.span, cmt_derefd, @@ -770,8 +829,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { expr: &ast::Expr, receiver: &ast::Expr, args: &[Gc]) - -> bool - { + -> bool { if !self.typer.is_method_call(expr.id) { return false; } @@ -782,11 +840,18 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { // methods are implicitly autoref'd which sadly does not use // adjustments, so we must hardcode the borrow here. - let r = ty::ReScope(expr.id); + let r = match self.typer.loop_analysis() { + None => ty::ReStatic, + Some(loop_analysis) => { + ty::ReSemeRegion(SemeRegion::from_scope(self.typer.tcx(), + loop_analysis, + expr.id)) + } + }; let bk = ty::ImmBorrow; for arg in args.iter() { - self.borrow_expr(&**arg, r, bk, OverloadedOperator); + self.borrow_expr(&**arg, &r, bk, OverloadedOperator); } return true; } @@ -839,8 +904,12 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { (ty::ty_region(tcx, pat.span, pat_ty), ty::BorrowKind::from_mutbl(m)) }; - delegate.borrow(pat.id, pat.span, cmt_pat, - r, bk, RefBinding); + delegate.borrow(pat.id, + pat.span, + cmt_pat, + &r, + bk, + RefBinding); } ast::PatIdent(ast::BindByValue(_), _, _) => { let mode = copy_or_move(typer.tcx(), cmt_pat.ty, PatBindingMove); @@ -892,9 +961,12 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { // to just require that people call // `vec.pop()` or `vec.unshift()`. let slice_bk = ty::BorrowKind::from_mutbl(slice_mutbl); - delegate.borrow(pat.id, pat.span, - slice_cmt, slice_r, - slice_bk, RefBinding); + delegate.borrow(pat.id, + pat.span, + slice_cmt, + &slice_r, + slice_bk, + RefBinding); } _ => { } } @@ -937,7 +1009,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { self.delegate.borrow(closure_expr.id, closure_expr.span, cmt_var, - upvar_borrow.region, + &upvar_borrow.region, upvar_borrow.kind, ClosureCapture(freevar.span)); } diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs index 2c79c655a9992..d8d3e0434603a 100644 --- a/src/librustc/middle/graph.rs +++ b/src/librustc/middle/graph.rs @@ -50,12 +50,13 @@ pub struct Node { pub struct Edge { next_edge: [EdgeIndex, ..2], // see module comment - source: NodeIndex, - target: NodeIndex, + pub source: NodeIndex, + pub target: NodeIndex, pub data: E, } -#[deriving(Clone, PartialEq, Show)] +#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Show, Decodable, + Encodable)] pub struct NodeIndex(pub uint); pub static InvalidNodeIndex: NodeIndex = NodeIndex(uint::MAX); @@ -64,11 +65,21 @@ pub struct EdgeIndex(pub uint); pub static InvalidEdgeIndex: EdgeIndex = EdgeIndex(uint::MAX); // Use a private field here to guarantee no more instances are created: -#[deriving(Show)] +#[deriving(PartialEq, Eq, Show)] pub struct Direction { repr: uint } pub static Outgoing: Direction = Direction { repr: 0 }; pub static Incoming: Direction = Direction { repr: 1 }; +impl Direction { + pub fn reverse(&self) -> Direction { + if *self == Outgoing { + Incoming + } else { + Outgoing + } + } +} + impl NodeIndex { fn get(&self) -> uint { let NodeIndex(v) = *self; v } /// Returns unique id (unique with respect to the graph holding associated node). diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 5814b6b02fe38..0bce543f8626f 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -279,12 +279,15 @@ fn with_appropriate_checker(cx: &Context, } fn check_for_block(cx: &Context, fv: &freevar_entry, - bounds: ty::BuiltinBounds, region: ty::Region) { + bounds: ty::BuiltinBounds, + region: &ty::Region) { let id = fv.def.def_id().node; let var_t = ty::node_id_to_type(cx.tcx, id); // FIXME(#3569): Figure out whether the implicit borrow is actually // mutable. Currently we assume all upvars are referenced mutably. - let implicit_borrowed_type = ty::mk_mut_rptr(cx.tcx, region, var_t); + let implicit_borrowed_type = ty::mk_mut_rptr(cx.tcx, + (*region).clone(), + var_t); check_freevar_bounds(cx, fv.span, implicit_borrowed_type, bounds, Some(var_t)); } @@ -299,14 +302,16 @@ fn with_appropriate_checker(cx: &Context, match ty::get(fty).sty { ty::ty_closure(box ty::ClosureTy { store: ty::UniqTraitStore, - bounds: bounds, + bounds: ref bounds, .. }) => { b(|cx, fv| check_for_uniq(cx, fv, bounds.builtin_bounds)) } ty::ty_closure(box ty::ClosureTy { - store: ty::RegionTraitStore(region, _), bounds, .. + store: ty::RegionTraitStore(ref region, _), + ref bounds, + .. }) => b(|cx, fv| check_for_block(cx, fv, bounds.builtin_bounds, region)), ty::ty_bare_fn(_) => { @@ -558,7 +563,7 @@ fn check_trait_cast(cx: &mut Context, match ty::get(target_ty).sty { ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => { match ty::get(ty).sty { - ty::ty_trait(box ty::TyTrait { bounds, .. }) => { + ty::ty_trait(box ty::TyTrait { ref bounds, .. }) => { match cx.tcx.vtable_map.borrow().find(&method_call) { None => { cx.tcx.sess.span_bug(span, diff --git a/src/librustc/middle/loop_analysis.rs b/src/librustc/middle/loop_analysis.rs new file mode 100644 index 0000000000000..fcc67a647852d --- /dev/null +++ b/src/librustc/middle/loop_analysis.rs @@ -0,0 +1,421 @@ +// Copyright 2014 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. + +//! A loop nesting tree. + +use middle::graph::{Graph, NodeIndex}; +use middle::ty::ctxt; +use util::nodemap::NodeMap; + +use syntax::ast::{Block, Decl, DeclItem, DeclLocal, Expr, ExprAddrOf}; +use syntax::ast::{ExprAgain, ExprAssign, ExprAssignOp, ExprBinary, ExprBlock}; +use syntax::ast::{ExprBox, ExprBreak, ExprCall, ExprCast, ExprField}; +use syntax::ast::{ExprFnBlock, ExprForLoop, ExprIf, ExprIndex, ExprInlineAsm}; +use syntax::ast::{ExprLit, ExprLoop, ExprMac, ExprMatch, ExprMethodCall}; +use syntax::ast::{ExprParen, ExprPath, ExprProc, ExprRepeat, ExprRet}; +use syntax::ast::{ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn, ExprVec}; +use syntax::ast::{ExprWhile, NodeId, Stmt, StmtDecl, StmtExpr, StmtMac}; +use syntax::ast::{StmtSemi}; + +pub struct LoopAnalysis { + /// A loop nesting tree. + graph: Graph, + /// The outermost loop node. + entry: NodeIndex, + /// A mapping from scope ID to index in the graph. + scope_map: NodeMap, +} + +#[allow(dead_code)] +pub struct LoopAnalysisNode { + /// The ID of the expression that defines the loop. + expr_id: NodeId, + /// The ID of the scope that encompasses the loop (i.e. the loop body). + scope_id: NodeId, + /// The kind of loop that this is. + kind: LoopKind, + /// The loop exits immediately nested inside this loop. Note that this + /// may not encompass *all* the exits of this loop, because of labeled + /// break and continue as well as early return. To find all the exits of + /// a loop, check for all of its descendants' exits as well. + exits: Vec, +} + +#[deriving(PartialEq, Eq)] +enum LoopKind { + /// A function, closure, or constant item (not actually a loop). + Function, + /// A `loop` loop. + Loop, + /// A `while` loop. + While, + /// A `for` loop. + For, +} + +#[allow(dead_code)] +struct LoopExit { + /// The kind of loop exit that this is. + kind: LoopExitKind, + /// The ID of the expression that exits the loop. If this is the normal + /// exit, this will be the ID of the block. + expr_id: NodeId, + /// The ID of the loop that this exits. + loop_id: NodeId, +} + +enum LoopExitKind { + NormalExit, + ContinueExit, + BreakExit, + ReturnExit, +} + +pub struct LoopAnalyzer<'a> { + analysis: LoopAnalysis, + tcx: &'a ctxt, +} + +impl<'a> LoopAnalyzer<'a> { + pub fn new(tcx: &ctxt) -> LoopAnalyzer { + LoopAnalyzer { + analysis: LoopAnalysis { + graph: Graph::new(), + entry: NodeIndex(-1), + scope_map: NodeMap::new(), + }, + tcx: tcx, + } + } + + pub fn analyze_block(mut self, block: &Block) -> LoopAnalysis { + let entry = self.add_node(Function, block.id, block.id, None); + self.analysis.entry = entry; + self.scan_block(block, entry); + self.analysis + } + + pub fn analyze_expr(mut self, expr: &Expr) -> LoopAnalysis { + let entry = self.add_node(Function, expr.id, expr.id, None); + self.analysis.entry = entry; + self.scan_expr(expr, entry); + self.analysis + } + + fn scan_block(&mut self, block: &Block, parent: NodeIndex) { + for stmt in block.stmts.iter() { + self.scan_stmt(&**stmt, parent) + } + match block.expr { + None => {} + Some(ref expr) => self.scan_expr(&**expr, parent), + } + } + + fn scan_stmt(&mut self, stmt: &Stmt, parent: NodeIndex) { + match stmt.node { + StmtDecl(ref decl, _) => self.scan_decl(&**decl, parent), + StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => { + self.scan_expr(&**expr, parent) + } + StmtMac(..) => { + self.tcx.sess.span_bug(stmt.span, "unexpanded macro") + } + } + } + + fn scan_decl(&mut self, decl: &Decl, parent: NodeIndex) { + match decl.node { + DeclLocal(ref local) => { + match local.init { + None => {} + Some(ref init) => self.scan_expr(&**init, parent), + } + } + DeclItem(_) => {} + } + } + + fn scan_expr(&mut self, expr: &Expr, parent: NodeIndex) { + match expr.node { + // Loops: + ExprWhile(ref cond, ref body, _) => { + self.scan_expr(&**cond, parent); + let loop_index = self.add_node(While, + expr.id, + body.id, + Some(parent)); + self.scan_block(&**body, loop_index); + } + ExprForLoop(_, ref head, ref body, _) => { + self.scan_expr(&**head, parent); + let loop_index = self.add_node(For, + expr.id, + body.id, + Some(parent)); + self.scan_block(&**body, loop_index); + } + ExprLoop(ref body, _) => { + let loop_index = self.add_node(Loop, + expr.id, + body.id, + Some(parent)); + self.scan_block(&**body, loop_index); + } + + // Functions: + ExprFnBlock(_, _, ref body) | + ExprProc(_, ref body) | + ExprUnboxedFn(_, _, _, ref body) => { + let fn_index = self.add_node(Function, + expr.id, + body.id, + Some(parent)); + self.scan_block(&**body, fn_index); + } + + // Loop exits: + ExprBreak(label) | ExprAgain(label) => { + let loop_index = if label.is_none() { + parent + } else { + self.find_enclosing_loop(self.tcx + .def_map + .borrow() + .get(&expr.id) + .def_id() + .node) + }; + let exit = LoopExit { + kind: match expr.node { + ExprAgain(_) => ContinueExit, + ExprBreak(_) => BreakExit, + _ => { + self.tcx.sess.bug("non-again/break loop exit") + } + }, + expr_id: expr.id, + loop_id: self.analysis + .graph + .node_data(loop_index) + .expr_id, + }; + self.analysis.graph.mut_node_data(parent).exits.push(exit) + } + ExprRet(ref value) => { + match *value { + None => {} + Some(ref value) => self.scan_expr(&**value, parent), + } + let parent = self.analysis.graph.mut_node_data(parent); + parent.exits.push(LoopExit { + kind: ReturnExit, + expr_id: expr.id, + loop_id: self.tcx + .region_maps + .enclosing_function(parent.expr_id), + }) + } + + // Others: + ExprBox(ref lhs, ref rhs) | + ExprBinary(_, ref lhs, ref rhs) | + ExprAssign(ref lhs, ref rhs) | + ExprAssignOp(_, ref lhs, ref rhs) | + ExprIndex(ref lhs, ref rhs) | + ExprRepeat(ref lhs, ref rhs) => { + self.scan_expr(&**lhs, parent); + self.scan_expr(&**rhs, parent) + } + ExprVec(ref subs) | + ExprMethodCall(_, _, ref subs) | + ExprTup(ref subs) => { + for sub in subs.iter() { + self.scan_expr(&**sub, parent) + } + } + ExprCall(ref callee, ref args) => { + self.scan_expr(&**callee, parent); + for arg in args.iter() { + self.scan_expr(&**arg, parent) + } + } + ExprUnary(_, ref sub) | + ExprCast(ref sub, _) | + ExprField(ref sub, _, _) | + ExprAddrOf(_, ref sub) | + ExprParen(ref sub) => self.scan_expr(&**sub, parent), + ExprIf(ref sub, ref block, ref sub_opt) => { + self.scan_expr(&**sub, parent); + self.scan_block(&**block, parent); + match *sub_opt { + None => {} + Some(ref els) => self.scan_expr(&**els, parent), + } + } + ExprMatch(ref sub, ref arms) => { + self.scan_expr(&**sub, parent); + for arm in arms.iter() { + match arm.guard { + None => {} + Some(ref guard) => self.scan_expr(&**guard, parent), + } + self.scan_expr(&*arm.body, parent) + } + } + ExprBlock(ref block) => self.scan_block(&**block, parent), + ExprPath(_) | ExprLit(..) => {} + ExprInlineAsm(ref asm) => { + for &(_, output, _) in asm.outputs.iter() { + self.scan_expr(&*output, parent) + } + for &(_, input) in asm.inputs.iter() { + self.scan_expr(&*input, parent) + } + } + ExprStruct(_, ref fields, ref base) => { + for field in fields.iter() { + self.scan_expr(&*field.expr, parent) + } + match *base { + None => {} + Some(ref base) => self.scan_expr(&**base, parent), + } + } + ExprMac(..) => { + self.tcx.sess.span_bug(expr.span, "unexpanded macro") + } + } + } + + fn add_node(&mut self, + kind: LoopKind, + expr_id: NodeId, + scope_id: NodeId, + parent: Option) + -> NodeIndex { + let node_index = self.analysis.graph.add_node(LoopAnalysisNode { + expr_id: expr_id, + scope_id: scope_id, + kind: kind, + exits: vec![ + LoopExit { + kind: NormalExit, + expr_id: scope_id, + loop_id: scope_id, + } + ], + }); + match parent { + None => {} + Some(parent) => { + self.analysis.graph.add_edge(parent, node_index, ()); + } + } + self.analysis.scope_map.insert(scope_id, node_index); + node_index + } + + fn find_enclosing_loop(&self, node_id: NodeId) -> NodeIndex { + let mut scope_id = node_id; + loop { + match self.analysis.scope_map.find(&scope_id) { + Some(scope_index) => return *scope_index, + None => {} + } + match self.tcx.region_maps.opt_encl_scope(scope_id) { + Some(encl_scope_id) => scope_id = encl_scope_id, + None => { + self.tcx.sess.span_bug(self.tcx.map.span(node_id), + "no enclosing loop") + } + } + } + } +} + +impl LoopAnalysis { + pub fn scope_exits(&self, tcx: &ctxt, scope_id: NodeId) -> Vec { + fn search(this: &LoopAnalysis, + tcx: &ctxt, + node_index: NodeIndex, + scope_id: NodeId, + accumulator: &mut Vec) { + for exit in this.graph.node_data(node_index).exits.iter() { + if tcx.region_maps.is_subscope_of(scope_id, exit.loop_id) { + accumulator.push(exit.expr_id) + } + } + this.graph.each_outgoing_edge(node_index, |_, edge| { + if this.graph.node_data(edge.target).kind != Function { + search(this, tcx, edge.target, scope_id, accumulator); + } + true + }); + } + + // Find the innermost enclosing loop. + let mut accumulator = Vec::new(); + let mut current_scope = scope_id; + loop { + match self.scope_map.find(¤t_scope) { + None => {} + Some(node_index) if scope_id == current_scope => { + // The scope that was passed to us precisely describes a + // loop, so just find its exits. + search(self, + tcx, + *node_index, + current_scope, + &mut accumulator); + break; + } + Some(node_index) => { + // The scope that was passed to us describes some scope + // outside of a loop. Start with the main exit of that + // scope, and add to it all exits of the loop that leave + // the scope. + accumulator.push(scope_id); + self.graph.each_outgoing_edge(*node_index, |_, edge| { + let node_data = self.graph.node_data(edge.target); + if node_data.kind != Function { + let loop_id = node_data.expr_id; + if tcx.region_maps.is_subscope_of(loop_id, + scope_id) { + search(self, + tcx, + edge.target, + scope_id, + &mut accumulator); + } + } + true + }); + break; + } + } + match tcx.region_maps.opt_encl_scope(current_scope) { + None => { + tcx.sess + .span_bug(tcx.map.span(scope_id), + format!("didn't find any outer scope in \ + loop analysis (failed scope was \ + {})", + tcx.map.node_to_string( + current_scope)).as_slice()) + } + Some(encl_scope) => current_scope = encl_scope, + } + } + + accumulator + } +} + diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 23cab419aa2c7..a7dd69b60f7df 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -64,6 +64,8 @@ use middle::def; use middle::freevars; +use middle::loop_analysis::LoopAnalysis; +use middle::seme_region::SemeRegion; use middle::ty; use middle::typeck; use util::nodemap::{DefIdMap, NodeMap}; @@ -180,16 +182,16 @@ pub fn opt_deref_kind(t: ty::t) -> Option { Some(deref_ptr(OwnedPtr)) } - ty::ty_rptr(r, mt) => { + ty::ty_rptr(ref r, mt) => { let kind = ty::BorrowKind::from_mutbl(mt.mutbl); - Some(deref_ptr(BorrowedPtr(kind, r))) + Some(deref_ptr(BorrowedPtr(kind, (*r).clone()))) } ty::ty_closure(box ty::ClosureTy { - store: ty::RegionTraitStore(r, _), + store: ty::RegionTraitStore(ref r, _), .. }) => { - Some(deref_ptr(BorrowedPtr(ty::ImmBorrow, r))) + Some(deref_ptr(BorrowedPtr(ty::ImmBorrow, (*r).clone()))) } ty::ty_box(..) => { @@ -265,17 +267,18 @@ pub type McResult = Result; * can be sure that only `Ok` results will occur. */ pub trait Typer { - fn tcx<'a>(&'a self) -> &'a ty::ctxt; + fn tcx(&self) -> &ty::ctxt; fn node_ty(&self, id: ast::NodeId) -> McResult; - fn node_method_ty(&self, method_call: typeck::MethodCall) -> Option; - fn adjustments<'a>(&'a self) -> &'a RefCell>; + fn node_method_ty(&self, method_call: typeck::MethodCall) + -> Option; + fn adjustments(&self) -> &RefCell>; fn is_method_call(&self, id: ast::NodeId) -> bool; fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option; fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow; fn capture_mode(&self, closure_expr_id: ast::NodeId) -> freevars::CaptureMode; - fn unboxed_closures<'a>(&'a self) - -> &'a RefCell>; + fn unboxed_closures(&self) -> &RefCell>; + fn loop_analysis(&self) -> Option<&LoopAnalysis>; } impl MutabilityCategory { @@ -295,8 +298,8 @@ impl MutabilityCategory { } pub fn from_pointer_kind(base_mutbl: MutabilityCategory, - ptr: PointerKind) -> MutabilityCategory { - match ptr { + ptr: &PointerKind) -> MutabilityCategory { + match *ptr { OwnedPtr => { base_mutbl.inherit() } @@ -568,14 +571,14 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { // Decide whether to use implicit reference or by copy/move // capture for the upvar. This, combined with the onceness, // determines whether the closure can move out of it. - let var_is_refd = match (closure_ty.store, closure_ty.onceness) { + let var_is_refd = match (&closure_ty.store, closure_ty.onceness) { // Many-shot stack closures can never move out. - (ty::RegionTraitStore(..), ast::Many) => true, + (&ty::RegionTraitStore(..), ast::Many) => true, // 1-shot stack closures can move out. - (ty::RegionTraitStore(..), ast::Once) => false, + (&ty::RegionTraitStore(..), ast::Once) => false, // Heap closures always capture by copy/move, and can // move out if they are once. - (ty::UniqTraitStore, _) => false, + (&ty::UniqTraitStore, _) => false, }; if var_is_refd { @@ -670,21 +673,21 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { let upvar_ty = ty::mk_err(); let base_cmt = Rc::new(cmt_ { - id:id, - span:span, - cat:cat_upvar(upvar_id, upvar_borrow), - mutbl:McImmutable, - ty:upvar_ty, + id: id, + span: span, + cat: cat_upvar(upvar_id, upvar_borrow.clone()), + mutbl: McImmutable, + ty: upvar_ty, }); - let ptr = BorrowedPtr(upvar_borrow.kind, upvar_borrow.region); + let ptr = BorrowedPtr(upvar_borrow.kind, upvar_borrow.region.clone()); let deref_cmt = Rc::new(cmt_ { - id:id, - span:span, - cat:cat_deref(base_cmt, 0, ptr), - mutbl:MutabilityCategory::from_borrow_kind(upvar_borrow.kind), - ty:var_ty, + id: id, + span: span, + cat: cat_deref(base_cmt, 0, ptr), + mutbl: MutabilityCategory::from_borrow_kind(upvar_borrow.kind), + ty: var_ty, }); Ok(deref_cmt) @@ -699,7 +702,20 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { Some(scope) => { match ty::get(expr_ty).sty { ty::ty_vec(_, Some(0)) => self.cat_rvalue(id, span, ty::ReStatic, expr_ty), - _ => self.cat_rvalue(id, span, ty::ReScope(scope), expr_ty) + _ => { + let rvalue_region = + match self.typer.loop_analysis() { + None => ty::ReStatic, + Some(loop_analysis) => { + ty::ReSemeRegion( + SemeRegion::from_scope( + self.typer.tcx(), + loop_analysis, + scope)) + } + }; + self.cat_rvalue(id, span, rvalue_region, expr_ty) + } } } None => { @@ -800,7 +816,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { }; // for unique ptrs, we inherit mutability from the // owning reference. - (MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr), + (MutabilityCategory::from_pointer_kind(base_cmt.mutbl, &ptr), cat_deref(base_cmt, deref_cnt, ptr)) } deref_interior(interior) => { @@ -885,16 +901,17 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { base_cmt: cmt) -> cmt { match deref_kind(self.tcx(), base_cmt.ty) { - deref_ptr(ptr) => { + deref_ptr(ref ptr) => { // for unique ptrs, we inherit mutability from the // owning reference. - let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr); + let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl, + ptr); // the deref is explicit in the resulting cmt Rc::new(cmt_ { id:elt.id(), span:elt.span(), - cat:cat_deref(base_cmt.clone(), 0, ptr), + cat:cat_deref(base_cmt.clone(), 0, (*ptr).clone()), mutbl:m, ty: match ty::deref(base_cmt.ty, false) { Some(mt) => mt.ty, @@ -942,10 +959,12 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { */ match ty::get(slice_ty).sty { - ty::ty_rptr(r, ref mt) => match ty::get(mt.ty).sty { - ty::ty_vec(_, None) => (mt.mutbl, r), - _ => vec_slice_info(tcx, pat, mt.ty), - }, + ty::ty_rptr(ref r, ref mt) => { + match ty::get(mt.ty).sty { + ty::ty_vec(_, None) => (mt.mutbl, (*r).clone()), + _ => vec_slice_info(tcx, pat, mt.ty), + } + } _ => { tcx.sess.span_bug(pat.span, @@ -1179,13 +1198,13 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { cat_arg(..) => { "argument".to_string() } - cat_deref(ref base, _, pk) => { + cat_deref(ref base, _, ref pk) => { match base.cat { cat_upvar(..) => { "captured outer variable".to_string() } _ => { - match pk { + match *pk { Implicit(..) => { "dereference (dereference is implicit, due to indexing)".to_string() } @@ -1336,16 +1355,19 @@ impl Repr for cmt_ { impl Repr for categorization { fn repr(&self, tcx: &ty::ctxt) -> String { match *self { + cat_rvalue(ref region) => format!("rvalue({})", region.repr(tcx)), cat_static_item | - cat_rvalue(..) | cat_copied_upvar(..) | cat_local(..) | cat_upvar(..) | cat_arg(..) => { format!("{:?}", *self) } - cat_deref(ref cmt, derefs, ptr) => { - format!("{}-{}{}->", cmt.cat.repr(tcx), ptr_sigil(ptr), derefs) + cat_deref(ref cmt, derefs, ref ptr) => { + format!("{}-{}{}->", + cmt.cat.repr(tcx), + ptr_sigil(ptr), + derefs) } cat_interior(ref cmt, interior) => { format!("{}.{}", cmt.cat.repr(tcx), interior.repr(tcx)) @@ -1360,8 +1382,8 @@ impl Repr for categorization { } } -pub fn ptr_sigil(ptr: PointerKind) -> &'static str { - match ptr { +pub fn ptr_sigil(ptr: &PointerKind) -> &'static str { + match *ptr { OwnedPtr => "Box", GcPtr => "Gc", BorrowedPtr(ty::ImmBorrow, _) | diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 21bfcfeec70b5..083ccae147a81 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -22,6 +22,8 @@ Most of the documentation on regions can be found in use driver::session::Session; +use middle::loop_analysis::LoopAnalysis; +use middle::seme_region::SemeRegion; use middle::ty::{FreeRegion}; use middle::ty; use util::nodemap::NodeMap; @@ -82,6 +84,11 @@ pub struct RegionMaps { free_region_map: RefCell>>, rvalue_scopes: RefCell>, terminating_scopes: RefCell>, + + /// Maps the outermost scopes of functions to the IDs of the functions + /// themselves. This is used to find the appropriate loop analysis for a + /// scope. + function_scopes: RefCell>, } #[deriving(Clone)] @@ -160,6 +167,19 @@ impl RegionMaps { } } + /// Returns the ID of the innermost function that encloses this scope. + pub fn enclosing_function(&self, mut id: ast::NodeId) -> ast::NodeId { + loop { + match self.function_scopes.borrow().find(&id) { + Some(&r) => return r, + None => {} + } + id = self.opt_encl_scope(id) + .expect("RegionMaps::enclosing_function(): id doesn't \ + seem to be in a function") + } + } + pub fn var_scope(&self, var_id: ast::NodeId) -> ast::NodeId { /*! * Returns the lifetime of the local variable `var_id` @@ -206,11 +226,15 @@ impl RegionMaps { return Some(id); } - pub fn var_region(&self, id: ast::NodeId) -> ty::Region { + pub fn var_region(&self, + tcx: &ty::ctxt, + loop_analysis: Option<&LoopAnalysis>, + id: ast::NodeId) + -> ty::Region { //! Returns the lifetime of the variable `id`. - let scope = ty::ReScope(self.var_scope(id)); - debug!("var_region({}) = {:?}", id, scope); + let scope = scope_region(tcx, loop_analysis, self.var_scope(id)); + debug!("var_region({}) = {}", id, scope); scope } @@ -260,8 +284,9 @@ impl RegionMaps { } pub fn is_subregion_of(&self, - sub_region: ty::Region, - super_region: ty::Region) + tcx: &ty::ctxt, + sub_region: &ty::Region, + super_region: &ty::Region) -> bool { /*! * Determines whether one region is a subregion of another. This is @@ -272,27 +297,39 @@ impl RegionMaps { debug!("is_subregion_of(sub_region={:?}, super_region={:?})", sub_region, super_region); - sub_region == super_region || { + *sub_region == *super_region || { match (sub_region, super_region) { - (ty::ReEmpty, _) | - (_, ty::ReStatic) => { + (&ty::ReEmpty, _) | + (_, &ty::ReStatic) => { true } - (ty::ReScope(sub_scope), ty::ReScope(super_scope)) => { + (&ty::ReSemeRegion(ref sub_seme_region), + &ty::ReSemeRegion(ref super_seme_region)) => { + // FIXME(pcwalton): Make this more precise. + let sub_scope = sub_seme_region.lub_scope(tcx); + let super_scope = super_seme_region.lub_scope(tcx); self.is_subscope_of(sub_scope, super_scope) } - (ty::ReScope(sub_scope), ty::ReFree(ref fr)) => { + (&ty::ReSemeRegion(ref sub_seme_region), + &ty::ReFree(ref fr)) => { + let sub_scope = sub_seme_region.lub_scope(tcx); self.is_subscope_of(sub_scope, fr.scope_id) } - (ty::ReFree(sub_fr), ty::ReFree(super_fr)) => { + (&ty::ReFree(sub_fr), &ty::ReFree(super_fr)) => { self.sub_free_region(sub_fr, super_fr) } - (ty::ReEarlyBound(param_id_a, param_space_a, index_a, _), - ty::ReEarlyBound(param_id_b, param_space_b, index_b, _)) => { + (&ty::ReEarlyBound(param_id_a, + param_space_a, + index_a, + _), + &ty::ReEarlyBound(param_id_b, + param_space_b, + index_b, + _)) => { // This case is used only to make sure that explicitly- // specified `Self` types match the real self type in // implementations. @@ -421,6 +458,13 @@ fn resolve_arm(visitor: &mut RegionResolutionVisitor, cx: Context) { visitor.region_maps.mark_as_terminating_scope(arm.body.id); + record_superlifetime(visitor, cx, arm.id, arm.span); + + let new_cx = Context { + var_parent: Some(arm.id), + parent: Some(arm.id), + }; + match arm.guard { Some(expr) => { visitor.region_maps.mark_as_terminating_scope(expr.id); @@ -428,7 +472,7 @@ fn resolve_arm(visitor: &mut RegionResolutionVisitor, None => { } } - visit::walk_arm(visitor, arm, cx); + visit::walk_arm(visitor, arm, new_cx); } fn resolve_pat(visitor: &mut RegionResolutionVisitor, @@ -840,11 +884,13 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor, cx } }; + + visitor.region_maps.function_scopes.borrow_mut().insert(body.id, id); + visitor.visit_block(body, body_cx); } impl<'a> Visitor for RegionResolutionVisitor<'a> { - fn visit_block(&mut self, b: &Block, cx: Context) { resolve_block(self, b, cx); } @@ -881,6 +927,7 @@ pub fn resolve_crate(sess: &Session, krate: &ast::Crate) -> RegionMaps { free_region_map: RefCell::new(HashMap::new()), rvalue_scopes: RefCell::new(NodeMap::new()), terminating_scopes: RefCell::new(HashSet::new()), + function_scopes: RefCell::new(NodeMap::new()), }; { let mut visitor = RegionResolutionVisitor { @@ -905,3 +952,15 @@ pub fn resolve_inlined_item(sess: &Session, visit::walk_inlined_item(&mut visitor, item, cx); } +pub fn scope_region(tcx: &ty::ctxt, + loop_analysis: Option<&LoopAnalysis>, + id: ast::NodeId) + -> ty::Region { + match loop_analysis { + None => ty::ReSemeRegion(SemeRegion::dummy()), + Some(loop_analysis) => { + ty::ReSemeRegion(SemeRegion::from_scope(tcx, loop_analysis, id)) + } + } +} + diff --git a/src/librustc/middle/seme_region.rs b/src/librustc/middle/seme_region.rs new file mode 100644 index 0000000000000..10826e343f082 --- /dev/null +++ b/src/librustc/middle/seme_region.rs @@ -0,0 +1,101 @@ +// Copyright 2014 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. + +//! Single-Entry-Multiple-Exit regions: i.e. the definition of a lifetime. + +use middle::loop_analysis::LoopAnalysis; +use middle::ty::ctxt; + +use syntax::ast::NodeId; + +#[deriving(PartialEq, Eq, Hash, Clone, Show, Decodable, Encodable)] +pub struct SemeRegion { + pub entry: NodeId, + pub exits: Vec, +} + +impl SemeRegion { + pub fn new(entry: NodeId, mut exits: Vec) -> SemeRegion { + exits.sort(); + SemeRegion { + entry: entry, + exits: exits, + } + } + + pub fn dummy() -> SemeRegion { + SemeRegion::new(-1, Vec::new()) + } + + /// Creates the SEME region corresponding to a scope, with all of its + /// exits. + pub fn from_scope(tcx: &ctxt, loop_analysis: &LoopAnalysis, id: NodeId) + -> SemeRegion { + SemeRegion::new(id, loop_analysis.scope_exits(tcx, id)) + } + + /// Returns the ID of the scope that encompasses the whole of this SEME + /// region. This is, obviously, a lossy conversion. + pub fn lub_scope(&self, tcx: &ctxt) -> NodeId { + let mut lub = self.entry; + for exit in self.exits.iter() { + match tcx.region_maps.nearest_common_ancestor(lub, *exit) { + Some(new_lub) => lub = new_lub, + None => { + tcx.sess.bug("SemeRegion::to_block(): didn't find a \ + nearest common ancestor") + } + } + } + lub + } + + // FIXME(pcwalton): This is imprecise; fill this in. + pub fn lub(&self, + other: &SemeRegion, + tcx: &ctxt, + loop_analysis: &LoopAnalysis) + -> Option { + let (this_id, other_id) = (self.lub_scope(tcx), other.lub_scope(tcx)); + match tcx.region_maps.nearest_common_ancestor(this_id, other_id) { + Some(ancestor_id) => { + return Some(SemeRegion::from_scope(tcx, + loop_analysis, + ancestor_id)) + } + None => return None, + } + } + + // FIXME(pcwalton): This is imprecise; fill this in. + // FIXME(pcwalton): This can be wrong if SEME regions don't span entire + // scopes. + pub fn glb(&self, + other: &SemeRegion, + tcx: &ctxt, + loop_analysis: &LoopAnalysis) + -> Option { + if *self == *other { + return Some((*self).clone()) + } + + let (this_id, other_id) = (self.lub_scope(tcx), other.lub_scope(tcx)); + match tcx.region_maps.nearest_common_ancestor(this_id, other_id) { + Some(ancestor_id) if this_id == ancestor_id => { + Some(SemeRegion::from_scope(tcx, loop_analysis, other_id)) + } + Some(ancestor_id) if other_id == ancestor_id => { + Some(SemeRegion::from_scope(tcx, loop_analysis, this_id)) + } + Some(_) | None => None, + } + } +} + diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index d992e840b4636..b3347150265bb 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -565,20 +565,20 @@ struct SubstFolder<'a> { impl<'a> TypeFolder for SubstFolder<'a> { fn tcx<'a>(&'a self) -> &'a ty::ctxt { self.tcx } - fn fold_region(&mut self, r: ty::Region) -> ty::Region { + fn fold_region(&mut self, r: &ty::Region) -> ty::Region { // Note: This routine only handles regions that are bound on // type declarations and other outer declarations, not those // 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_late_regions_in_fn_sig()`. - match r { + match *r { ty::ReEarlyBound(_, space, i, region_name) => { match self.substs.regions { ErasedRegions => ty::ReStatic, NonerasedRegions(ref regions) => match regions.opt_get(space, i) { - Some(t) => *t, + Some(t) => (*t).clone(), None => { let span = self.span.unwrap_or(DUMMY_SP); self.tcx().sess.span_bug( @@ -593,7 +593,7 @@ impl<'a> TypeFolder for SubstFolder<'a> { } } } - _ => r + _ => (*r).clone(), } } diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 040577e7048e1..4a5f260b1b307 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -881,7 +881,8 @@ fn compile_guard<'a, 'b>( m: &'a [Match<'a, 'b>], vals: &[ValueRef], chk: &FailureHandler, - has_genuine_default: bool) + has_genuine_default: bool, + arm_id: ast::NodeId) -> &'b Block<'b> { debug!("compile_guard(bcx={}, guard_expr={}, m={}, vals={})", bcx.to_str(), @@ -890,6 +891,7 @@ fn compile_guard<'a, 'b>( vec_map_to_string(vals, |v| bcx.val_to_string(*v))); let _indenter = indenter(); + bcx.fcx.push_ast_cleanup_scope(arm_id); let mut bcx = insert_lllocals(bcx, &data.bindings_map, None); let val = unpack_datum!(bcx, expr::trans(bcx, guard_expr)); @@ -902,6 +904,8 @@ fn compile_guard<'a, 'b>( } } + bcx = bcx.fcx.pop_and_trans_ast_cleanup_scope(bcx, arm_id); + with_cond(bcx, Not(bcx, val), |bcx| { // Guard does not match: remove all bindings from the lllocals table for (_, &binding_info) in data.bindings_map.iter() { @@ -959,7 +963,8 @@ fn compile_submatch<'a, 'b>( m.slice(1, m.len()), vals, chk, - has_genuine_default); + has_genuine_default, + data.arm.id); } _ => () } @@ -1222,7 +1227,7 @@ pub fn trans_match<'a>( bcx: &'a Block<'a>, match_expr: &ast::Expr, discr_expr: &ast::Expr, - arms: &[ast::Arm], + arms: &[Gc], dest: Dest) -> &'a Block<'a> { let _icx = push_ctxt("match::trans_match"); @@ -1259,7 +1264,7 @@ struct ReassignmentChecker { impl euv::Delegate for ReassignmentChecker { fn consume(&mut self, _: ast::NodeId, _: Span, _: mc::cmt, _: euv::ConsumeMode) {} fn consume_pat(&mut self, _: &ast::Pat, _: mc::cmt, _: euv::ConsumeMode) {} - fn borrow(&mut self, _: ast::NodeId, _: Span, _: mc::cmt, _: ty::Region, + fn borrow(&mut self, _: ast::NodeId, _: Span, _: mc::cmt, _: &ty::Region, _: ty::BorrowKind, _: euv::LoanCause) {} fn decl_without_init(&mut self, _: ast::NodeId, _: Span) {} @@ -1330,8 +1335,9 @@ fn create_bindings_map(bcx: &Block, pat: Gc, fn trans_match_inner<'a>(scope_cx: &'a Block<'a>, match_id: ast::NodeId, discr_expr: &ast::Expr, - arms: &[ast::Arm], - dest: Dest) -> &'a Block<'a> { + arms: &[Gc], + dest: Dest) + -> &'a Block<'a> { let _icx = push_ctxt("match::trans_match_inner"); let fcx = scope_cx.fcx; let mut bcx = scope_cx; @@ -1352,7 +1358,7 @@ fn trans_match_inner<'a>(scope_cx: &'a Block<'a>, let arm_datas: Vec = arms.iter().map(|arm| ArmData { bodycx: fcx.new_id_block("case_body", arm.body.id), - arm: arm, + arm: &**arm, bindings_map: create_bindings_map(bcx, *arm.pats.get(0), discr_expr, &*arm.body) }).collect(); @@ -1384,10 +1390,12 @@ fn trans_match_inner<'a>(scope_cx: &'a Block<'a>, let mut bcx = arm_data.bodycx; // insert bindings into the lllocals map and add cleanups - let cs = fcx.push_custom_cleanup_scope(); - bcx = insert_lllocals(bcx, &arm_data.bindings_map, Some(cleanup::CustomScope(cs))); + fcx.push_ast_cleanup_scope(arm_data.arm.id); + bcx = insert_lllocals(bcx, + &arm_data.bindings_map, + Some(cleanup::AstScope(arm_data.arm.id))); bcx = expr::trans_into(bcx, &*arm_data.arm.body, dest); - bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, cs); + bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, arm_data.arm.id); arm_cxs.push(bcx); } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 76e2266fcb92f..839833db60f98 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2388,13 +2388,16 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) // actually know the concrete type of Self thus we don't know how // many bytes to mark as dereferenceable so instead we just mark // it as nonnull which still holds true - ty::ty_rptr(b, ty::mt { ty: it, mutbl }) if match ty::get(it).sty { + ty::ty_rptr(ref b, ty::mt { + ty: it, + mutbl + }) if match ty::get(it).sty { ty::ty_param(_) => true, _ => false } && mutbl == ast::MutMutable => { attrs.arg(idx, llvm::NoAliasAttribute) .arg(idx, llvm::NonNullAttribute); - match b { + match *b { ReLateBound(_, BrAnon(_)) => { attrs.arg(idx, llvm::NoCaptureAttribute); } @@ -2407,7 +2410,7 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) // `&T` where `T` contains no `UnsafeCell` is immutable, and can be marked as both // `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on // memory dependencies rather than pointer equality - ty::ty_rptr(b, mt) if mt.mutbl == ast::MutMutable || + ty::ty_rptr(ref b, mt) if mt.mutbl == ast::MutMutable || !ty::type_contents(ccx.tcx(), mt.ty).interior_unsafe() => { let llsz = llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); @@ -2418,7 +2421,7 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) attrs.arg(idx, llvm::ReadOnlyAttribute); } - match b { + match *b { ReLateBound(_, BrAnon(_)) => { attrs.arg(idx, llvm::NoCaptureAttribute); } diff --git a/src/librustc/middle/trans/cleanup.rs b/src/librustc/middle/trans/cleanup.rs index 515413e03f060..639c21233f4d8 100644 --- a/src/librustc/middle/trans/cleanup.rs +++ b/src/librustc/middle/trans/cleanup.rs @@ -100,8 +100,31 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> { // now we just say that if there is already an AST scope on the stack, // this new AST scope had better be its immediate child. let top_scope = self.top_ast_scope(); - if top_scope.is_some() { - assert_eq!(self.ccx.tcx.region_maps.opt_encl_scope(id), top_scope); + match top_scope { + None => {} + Some(top_scope) => { + let encl_scope = self.ccx.tcx.region_maps.encl_scope(id); + if encl_scope != top_scope { + self.ccx + .tcx + .sess + .bug(format!("typeck expected enclosing scope to be \ + {}, but trans thinks it's {} when \ + pushing {}", + self.ccx + .tcx + .map + .node_to_string(encl_scope), + self.ccx + .tcx + .map + .node_to_string(top_scope), + self.ccx + .tcx + .map + .node_to_string(id)).as_slice()) + } + } } self.push_scope(CleanupScope::new(AstScopeKind(id))); diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index 17f1b6ca52669..2ca7aff368500 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -137,14 +137,14 @@ fn tuplify_box_ty(tcx: &ty::ctxt, t: ty::t) -> ty::t { } fn allocate_cbox<'a>(bcx: &'a Block<'a>, - store: ty::TraitStore, + store: &ty::TraitStore, cdata_ty: ty::t) -> Result<'a> { let _icx = push_ctxt("closure::allocate_cbox"); let tcx = bcx.tcx(); // Allocate and initialize the box: - match store { + match *store { ty::UniqTraitStore => { let ty = type_of(bcx.ccx(), cdata_ty); let size = llsize_of(bcx.ccx(), ty); @@ -172,7 +172,7 @@ pub struct ClosureResult<'a> { pub fn store_environment<'a>( bcx: &'a Block<'a>, bound_values: Vec , - store: ty::TraitStore) + store: &ty::TraitStore) -> ClosureResult<'a> { let _icx = push_ctxt("closure::store_environment"); let ccx = bcx.ccx(); @@ -231,9 +231,8 @@ pub fn store_environment<'a>( fn build_closure<'a>(bcx0: &'a Block<'a>, freevar_mode: freevars::CaptureMode, freevars: &Vec, - store: ty::TraitStore) - -> ClosureResult<'a> -{ + store: &ty::TraitStore) + -> ClosureResult<'a> { let _icx = push_ctxt("closure::build_closure"); // If we need to, package up the iterator body to call @@ -255,7 +254,7 @@ fn build_closure<'a>(bcx0: &'a Block<'a>, fn load_environment<'a>(bcx: &'a Block<'a>, cdata_ty: ty::t, freevars: &Vec, - store: ty::TraitStore) + store: &ty::TraitStore) -> &'a Block<'a> { let _icx = push_ctxt("closure::load_environment"); @@ -281,7 +280,7 @@ fn load_environment<'a>(bcx: &'a Block<'a>, let mut i = 0u; for freevar in freevars.iter() { let mut upvarptr = GEPi(bcx, llcdata, [0u, i]); - match store { + match *store { ty::RegionTraitStore(..) => { upvarptr = Load(bcx, upvarptr); } ty::UniqTraitStore => {} } @@ -355,7 +354,7 @@ fn fill_fn_pair(bcx: &Block, pair: ValueRef, llfn: ValueRef, llenvptr: ValueRef) pub fn trans_expr_fn<'a>( bcx: &'a Block<'a>, - store: ty::TraitStore, + store: &ty::TraitStore, decl: &ast::FnDecl, body: &ast::Block, id: ast::NodeId, diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index d92364b257010..468c42ce44612 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -19,6 +19,7 @@ use llvm::{True, False, Bool}; use middle::def; use middle::freevars; use middle::lang_items::LangItem; +use middle::loop_analysis::LoopAnalysis; use middle::mem_categorization as mc; use middle::subst; use middle::subst::Subst; @@ -533,6 +534,10 @@ impl<'a> mc::Typer for Block<'a> { -> freevars::CaptureMode { self.tcx().capture_modes.borrow().get_copy(&closure_expr_id) } + + fn loop_analysis(&self) -> Option<&LoopAnalysis> { + None + } } pub struct Result<'a> { diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 8403e84f7b655..5c7e7759f588c 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -456,12 +456,14 @@ impl TypeMap { let return_type_id = self.get_unique_type_id_as_string(return_type_id); unique_type_id.push_str(return_type_id.as_slice()); }, - ty::ty_closure(box ty::ClosureTy { fn_style, - onceness, - store, - ref bounds, - ref sig, - abi: _ }) => { + ty::ty_closure(box ty::ClosureTy { + fn_style, + onceness, + ref store, + ref bounds, + ref sig, + abi: _ + }) => { if fn_style == ast::UnsafeFn { unique_type_id.push_str("unsafe "); } @@ -470,7 +472,7 @@ impl TypeMap { unique_type_id.push_str("once "); } - match store { + match *store { ty::UniqTraitStore => unique_type_id.push_str("~|"), ty::RegionTraitStore(_, ast::MutMutable) => { unique_type_id.push_str("&mut|") @@ -872,7 +874,7 @@ pub fn create_captured_var_metadata(bcx: &Block, env_data_type: ty::t, env_pointer: ValueRef, env_index: uint, - closure_store: ty::TraitStore, + closure_store: &ty::TraitStore, span: Span) { if fn_should_be_ignored(bcx.fcx) { return; @@ -927,7 +929,7 @@ pub fn create_captured_var_metadata(bcx: &Block, llvm::LLVMDIBuilderCreateOpDeref(Type::i64(cx).to_ref())] }; - let address_op_count = match closure_store { + let address_op_count = match *closure_store { ty::RegionTraitStore(..) => { address_operations.len() } @@ -3783,12 +3785,13 @@ fn push_debuginfo_type_name(cx: &CrateContext, push_debuginfo_type_name(cx, sig.output, true, output); } }, - ty::ty_closure(box ty::ClosureTy { fn_style, - onceness, - store, - ref sig, - .. // omitting bounds ... - }) => { + ty::ty_closure(box ty::ClosureTy { + fn_style, + onceness, + ref store, + ref sig, + .. // omitting bounds ... + }) => { if fn_style == ast::UnsafeFn { output.push_str("unsafe "); } @@ -3798,7 +3801,7 @@ fn push_debuginfo_type_name(cx: &CrateContext, } let param_list_closing_char; - match store { + match *store { ty::UniqTraitStore => { output.push_str("proc("); param_list_closing_char = ')'; diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 4fe687da4b194..0ad73931bafc4 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -1014,7 +1014,12 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>, let store = ty::ty_closure_store(expr_ty); debug!("translating block function {} with type {}", expr_to_string(expr), expr_ty.repr(tcx)); - closure::trans_expr_fn(bcx, store, &**decl, &**body, expr.id, dest) + closure::trans_expr_fn(bcx, + &store, + &**decl, + &**body, + expr.id, + dest) } ast::ExprUnboxedFn(_, _, decl, body) => { closure::trans_unboxed_closure(bcx, &*decl, &*body, expr.id, dest) diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index f2a7f1dc4f8ee..c32c7a496486e 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -246,6 +246,7 @@ pub fn monomorphic_fn(ccx: &CrateContext, ast_map::NodeExpr(..) | ast_map::NodeStmt(..) | ast_map::NodeArg(..) | + ast_map::NodeArm(..) | ast_map::NodeBlock(..) | ast_map::NodePat(..) | ast_map::NodeLocal(..) => { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 72f6338f4c9c7..52f7327b378c0 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -22,16 +22,18 @@ use middle::freevars; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem}; use middle::lang_items::{FnOnceTraitLangItem, OpaqueStructLangItem}; use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem}; +use middle::loop_analysis::LoopAnalysis; use middle::mem_categorization as mc; use middle::resolve; use middle::resolve_lifetime; +use middle::seme_region::SemeRegion; use middle::stability; use middle::subst::{Subst, Substs, VecPerParamSpace}; use middle::subst; use middle::ty; use middle::typeck; use middle::ty_fold; -use middle::ty_fold::{TypeFoldable,TypeFolder}; +use middle::ty_fold::{TypeFoldable, TypeFolder}; use middle; use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string}; use util::ppaux::{trait_store_to_string, ty_to_string}; @@ -319,12 +321,12 @@ fn autoref_object_region(autoref: &AutoRef) -> (bool, bool, Option) { match autoref { &AutoUnsize(ref k) => (unsize_kind_is_object(k), false, None), &AutoUnsizeUniq(ref k) => (unsize_kind_is_object(k), true, None), - &AutoPtr(adj_r, _, Some(box ref autoref)) => { + &AutoPtr(ref adj_r, _, Some(box ref autoref)) => { let (b, u, r) = autoref_object_region(autoref); if r.is_some() || u { (b, u, r) } else { - (b, u, Some(adj_r)) + (b, u, Some((*adj_r).clone())) } } &AutoUnsafe(_, Some(box ref autoref)) => autoref_object_region(autoref), @@ -365,20 +367,28 @@ pub fn type_of_adjust(cx: &ctxt, adj: &AutoAdjustment) -> Option { fn type_of_autoref(cx: &ctxt, autoref: &AutoRef) -> Option { match autoref { &AutoUnsize(ref k) => match k { - &UnsizeVtable(bounds, def_id, ref substs) => { - Some(mk_trait(cx, def_id, substs.clone(), bounds)) + &UnsizeVtable(ref bounds, def_id, ref substs) => { + Some(mk_trait(cx, + def_id, + substs.clone(), + (*bounds).clone())) } _ => None }, &AutoUnsizeUniq(ref k) => match k { - &UnsizeVtable(bounds, def_id, ref substs) => { - Some(mk_uniq(cx, mk_trait(cx, def_id, substs.clone(), bounds))) + &UnsizeVtable(ref bounds, def_id, ref substs) => { + Some(mk_uniq(cx, mk_trait(cx, + def_id, + substs.clone(), + (*bounds).clone()))) } _ => None }, - &AutoPtr(r, m, Some(box ref autoref)) => { + &AutoPtr(ref r, m, Some(box ref autoref)) => { match type_of_autoref(cx, autoref) { - Some(t) => Some(mk_rptr(cx, r, mt {mutbl: m, ty: t})), + Some(t) => { + Some(mk_rptr(cx, (*r).clone(), mt {mutbl: m, ty: t})) + } None => None } } @@ -679,8 +689,8 @@ pub enum Region { /// region parameters. ReFree(FreeRegion), - /// A concrete region naming some expression within the current function. - ReScope(NodeId), + /// A concrete region naming a SEME region. + ReSemeRegion(SemeRegion), /// Static data that has an "infinite" lifetime. Top in the region lattice. ReStatic, @@ -1230,7 +1240,7 @@ pub struct ParameterEnvironment { /// indicates it must outlive at least the function body (the user /// may specify stronger requirements). This field indicates the /// region of the callee. - pub implicit_region_bound: ty::Region, + pub implicit_region_bound: ImplicitRegionBound, } impl ParameterEnvironment { @@ -1467,9 +1477,9 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { } let mut flags = 0u; - fn rflags(r: Region) -> uint { + fn rflags(r: &Region) -> uint { (has_regions as uint) | { - match r { + match *r { ty::ReInfer(_) => needs_infer as uint, _ => 0u } @@ -1485,14 +1495,14 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { subst::ErasedRegions => {} subst::NonerasedRegions(ref regions) => { for r in regions.iter() { - f |= rflags(*r) + f |= rflags(r) } } } return f; } fn flags_for_bounds(bounds: &ExistentialBounds) -> uint { - rflags(bounds.region_bound) + rflags(&bounds.region_bound) } match &st { &ty_nil | &ty_bool | &ty_char | &ty_int(_) | &ty_float(_) | &ty_uint(_) | @@ -1513,7 +1523,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { flags |= has_params as uint; } } - &ty_unboxed_closure(_, ref region) => flags |= rflags(*region), + &ty_unboxed_closure(_, ref region) => flags |= rflags(region), &ty_infer(_) => flags |= needs_infer as uint, &ty_enum(_, ref substs) | &ty_struct(_, ref substs) => { flags |= sflags(substs); @@ -1528,7 +1538,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { &ty_ptr(ref m) => { flags |= get(m.ty).flags; } - &ty_rptr(r, ref m) => { + &ty_rptr(ref r, ref m) => { flags |= rflags(r); flags |= get(m.ty).flags; } @@ -1541,7 +1551,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { } &ty_closure(ref f) => { match f.store { - RegionTraitStore(r, _) => { + RegionTraitStore(ref r, _) => { flags |= rflags(r); } _ => {} @@ -1830,10 +1840,10 @@ pub fn fold_ty(cx: &ctxt, t0: t, fldop: |t| -> t) -> t { f.fold_ty(t0) } -pub fn walk_regions_and_ty(cx: &ctxt, ty: t, fldr: |r: Region|, fldt: |t: t|) +pub fn walk_regions_and_ty(cx: &ctxt, ty: t, fldr: |r: &Region|, fldt: |t: t|) -> t { ty_fold::RegionFolder::general(cx, - |r| { fldr(r); r }, + |r| { fldr(r); (*r).clone() }, |t| { fldt(t); t }).fold_ty(ty) } @@ -2409,7 +2419,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { } } - ty_trait(box ty::TyTrait { bounds, .. }) => { + ty_trait(box ty::TyTrait { ref bounds, .. }) => { object_contents(cx, bounds) | TC::ReachesFfiUnsafe | TC::Nonsized } @@ -2417,7 +2427,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { tc_ty(cx, mt.ty, cache).unsafe_pointer() } - ty_rptr(r, ref mt) => { + ty_rptr(ref r, ref mt) => { TC::ReachesFfiUnsafe | match get(mt.ty).sty { ty_str => borrowed_contents(r, ast::MutImmutable), ty_vec(..) => tc_ty(cx, mt.ty, cache).reference(borrowed_contents(r, mt.mutbl)), @@ -2450,7 +2460,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { apply_lang_items(cx, did, res) } - ty_unboxed_closure(did, r) => { + ty_unboxed_closure(did, ref r) => { // FIXME(#14449): `borrowed_contents` below assumes `&mut` // unboxed closure. let upvars = unboxed_closure_upvars(cx, did); @@ -2586,7 +2596,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { } } - fn borrowed_contents(region: ty::Region, + fn borrowed_contents(region: &ty::Region, mutbl: ast::Mutability) -> TypeContents { /*! @@ -2598,19 +2608,19 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { ast::MutMutable => TC::ReachesMutable | TC::OwnsAffine, ast::MutImmutable => TC::None, }; - b | (TC::ReachesBorrowed).when(region != ty::ReStatic) + b | (TC::ReachesBorrowed).when(*region != ty::ReStatic) } fn closure_contents(cx: &ctxt, cty: &ClosureTy) -> TypeContents { // Closure contents are just like trait contents, but with potentially // even more stuff. - let st = object_contents(cx, cty.bounds); + let st = object_contents(cx, &cty.bounds); let st = match cty.store { UniqTraitStore => { st.owned_pointer() } - RegionTraitStore(r, mutbl) => { + RegionTraitStore(ref r, mutbl) => { st.reference(borrowed_contents(r, mutbl)) } }; @@ -2625,8 +2635,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { st | ot } - fn object_contents(cx: &ctxt, - bounds: ExistentialBounds) + fn object_contents(cx: &ctxt, bounds: &ExistentialBounds) -> TypeContents { // These are the type contents of the (opaque) interior kind_bounds_to_contents(cx, bounds.builtin_bounds, []) @@ -3169,7 +3178,7 @@ pub fn ty_fn_args(fty: t) -> Vec { pub fn ty_closure_store(fty: t) -> TraitStore { match get(fty).sty { - ty_closure(ref f) => f.store, + ty_closure(ref f) => f.store.clone(), ty_unboxed_closure(..) => { // Close enough for the purposes of all the callers of this // function (which is soon to be deprecated anyhow). @@ -3199,11 +3208,9 @@ pub fn is_fn_ty(fty: t) -> bool { } } -pub fn ty_region(tcx: &ctxt, - span: Span, - ty: t) -> Region { +pub fn ty_region(tcx: &ctxt, span: Span, ty: t) -> Region { match get(ty).sty { - ty_rptr(r, _) => r, + ty_rptr(ref r, _) => (*r).clone(), ref s => { tcx.sess.span_bug( span, @@ -3322,7 +3329,7 @@ pub fn adjust_ty(cx: &ctxt, return match adjustment { Some(adjustment) => { match *adjustment { - AutoAddEnv(store) => { + AutoAddEnv(ref store) => { match ty::get(unadjusted_ty).sty { ty::ty_bare_fn(ref b) => { let bounds = ty::ExistentialBounds { @@ -3332,12 +3339,14 @@ pub fn adjust_ty(cx: &ctxt, ty::mk_closure( cx, - ty::ClosureTy {fn_style: b.fn_style, - onceness: ast::Many, - store: store, - bounds: bounds, - sig: b.sig.clone(), - abi: b.abi}) + ty::ClosureTy { + fn_style: b.fn_style, + onceness: ast::Many, + store: (*store).clone(), + bounds: bounds, + sig: b.sig.clone(), + abi: b.abi, + }) } ref b => { cx.sess.bug( @@ -3390,12 +3399,12 @@ pub fn adjust_ty(cx: &ctxt, ty: ty::t, autoref: &AutoRef) -> ty::t{ match *autoref { - AutoPtr(r, m, ref a) => { + AutoPtr(ref r, m, ref a) => { let adjusted_ty = match a { &Some(box ref a) => adjust_for_autoref(cx, span, ty, a), &None => ty }; - mk_rptr(cx, r, mt { + mk_rptr(cx, (*r).clone(), mt { ty: adjusted_ty, mutbl: m }) @@ -3444,17 +3453,19 @@ pub fn unsize_ty(cx: &ctxt, format!("UnsizeStruct with bad sty: {}", ty_to_string(cx, ty)).as_slice()) }, - &UnsizeVtable(bounds, def_id, ref substs) => { - mk_trait(cx, def_id, substs.clone(), bounds) + &UnsizeVtable(ref bounds, def_id, ref substs) => { + mk_trait(cx, def_id, substs.clone(), (*bounds).clone()) } } } impl AutoRef { - pub fn map_region(&self, f: |Region| -> Region) -> AutoRef { + pub fn map_region(&self, f: |&Region| -> Region) -> AutoRef { match *self { - ty::AutoPtr(r, m, None) => ty::AutoPtr(f(r), m, None), - ty::AutoPtr(r, m, Some(ref a)) => ty::AutoPtr(f(r), m, Some(box a.map_region(f))), + ty::AutoPtr(ref r, m, None) => ty::AutoPtr(f(r), m, None), + ty::AutoPtr(ref r, m, Some(ref a)) => { + ty::AutoPtr(f(r), m, Some(box a.map_region(f))) + } ty::AutoUnsize(ref k) => ty::AutoUnsize(k.clone()), ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.clone()), ty::AutoUnsafe(m, None) => ty::AutoUnsafe(m, None), @@ -3801,7 +3812,7 @@ pub fn type_err_to_str(cx: &ctxt, err: &type_err) -> String { values.expected.to_string(), values.found.to_string()) } - terr_sigil_mismatch(values) => { + terr_sigil_mismatch(ref values) => { format!("expected {}, found {}", tstore_to_closure(&values.expected), tstore_to_closure(&values.found)) @@ -3864,8 +3875,8 @@ pub fn type_err_to_str(cx: &ctxt, err: &type_err) -> String { } terr_trait_stores_differ(_, ref values) => { format!("trait storage differs: expected `{}`, found `{}`", - trait_store_to_string(cx, (*values).expected), - trait_store_to_string(cx, (*values).found)) + trait_store_to_string(cx, &(*values).expected), + trait_store_to_string(cx, &(*values).found)) } terr_sorts(values) => { format!("expected {}, found {}", @@ -3913,30 +3924,38 @@ pub fn type_err_to_str(cx: &ctxt, err: &type_err) -> String { pub fn note_and_explain_type_err(cx: &ctxt, err: &type_err) { match *err { - terr_regions_does_not_outlive(subregion, superregion) => { + terr_regions_does_not_outlive(ref subregion, ref superregion) => { note_and_explain_region(cx, "", subregion, "..."); - note_and_explain_region(cx, "...does not necessarily outlive ", - superregion, ""); + note_and_explain_region(cx, + "...does not necessarily outlive ", + superregion, + ""); } - terr_regions_not_same(region1, region2) => { + terr_regions_not_same(ref region1, ref region2) => { note_and_explain_region(cx, "", region1, "..."); - note_and_explain_region(cx, "...is not the same lifetime as ", - region2, ""); + note_and_explain_region(cx, + "...is not the same lifetime as ", + region2, + ""); } - terr_regions_no_overlap(region1, region2) => { + terr_regions_no_overlap(ref region1, ref region2) => { note_and_explain_region(cx, "", region1, "..."); - note_and_explain_region(cx, "...does not overlap ", - region2, ""); + note_and_explain_region(cx, + "...does not overlap ", + region2, + ""); } - terr_regions_insufficiently_polymorphic(_, conc_region) => { + terr_regions_insufficiently_polymorphic(_, ref conc_region) => { note_and_explain_region(cx, "concrete lifetime that was found is ", - conc_region, ""); + conc_region, + ""); } - terr_regions_overly_polymorphic(_, conc_region) => { + terr_regions_overly_polymorphic(_, ref conc_region) => { note_and_explain_region(cx, "expected concrete lifetime is ", - conc_region, ""); + conc_region, + ""); } _ => {} } @@ -4671,7 +4690,7 @@ pub fn normalize_ty(cx: &ctxt, t: t) -> t { return t_norm; } - fn fold_region(&mut self, _: ty::Region) -> ty::Region { + fn fold_region(&mut self, _: &ty::Region) -> ty::Region { ty::ReStatic } @@ -5115,15 +5134,15 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 { macro_rules! byte( ($b:expr) => { ($b as u8).hash(&mut state) } ); macro_rules! hash( ($e:expr) => { $e.hash(&mut state) } ); - let region = |_state: &mut sip::SipState, r: Region| { - match r { + let region = |_state: &mut sip::SipState, r: &Region| { + match *r { ReStatic => {} ReEmpty | ReEarlyBound(..) | ReLateBound(..) | ReFree(..) | - ReScope(..) | + ReSemeRegion(..) | ReInfer(..) => { tcx.sess.bug("non-static region found when hashing a type") } @@ -5184,7 +5203,7 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 { byte!(12); mt(&mut state, m); } - ty_rptr(r, m) => { + ty_rptr(ref r, m) => { byte!(13); region(&mut state, r); mt(&mut state, m); @@ -5201,14 +5220,14 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 { hash!(c.bounds); match c.store { UniqTraitStore => byte!(0), - RegionTraitStore(r, m) => { + RegionTraitStore(ref r, m) => { byte!(1) region(&mut state, r); assert_eq!(m, ast::MutMutable); } } } - ty_trait(box ty::TyTrait { def_id: d, bounds, .. }) => { + ty_trait(box ty::TyTrait { def_id: d, ref bounds, .. }) => { byte!(17); did(&mut state, d); hash!(bounds); @@ -5229,7 +5248,7 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 { ty_open(_) => byte!(22), ty_infer(_) => unreachable!(), ty_err => byte!(23), - ty_unboxed_closure(d, r) => { + ty_unboxed_closure(d, ref r) => { byte!(24); did(&mut state, d); region(&mut state, r); @@ -5251,12 +5270,10 @@ impl Variance { } } -pub fn construct_parameter_environment( - tcx: &ctxt, - generics: &ty::Generics, - free_id: ast::NodeId) - -> ParameterEnvironment -{ +pub fn construct_parameter_environment(tcx: &ctxt, + generics: &ty::Generics, + free_id: ast::NodeId) + -> ParameterEnvironment { /*! See `ParameterEnvironment` struct def'n for details */ // @@ -5314,14 +5331,13 @@ pub fn construct_parameter_environment( return ty::ParameterEnvironment { free_substs: free_substs, bounds: bounds, - implicit_region_bound: ty::ReScope(free_id), + implicit_region_bound: ScopeImplicitRegionBound(free_id), }; fn push_region_params(regions: &mut VecPerParamSpace, space: subst::ParamSpace, free_id: ast::NodeId, - region_params: &[RegionParameterDef]) - { + region_params: &[RegionParameterDef]) { for r in region_params.iter() { regions.push(space, ty::free_region_from_def(free_id, r)); } @@ -5380,6 +5396,11 @@ pub fn construct_parameter_environment( } } +pub enum ImplicitRegionBound { + RegionImplicitRegionBound(ty::Region), + ScopeImplicitRegionBound(ast::NodeId), +} + impl BorrowKind { pub fn from_mutbl(m: ast::Mutability) -> BorrowKind { match m { @@ -5435,6 +5456,10 @@ impl mc::Typer for ty::ctxt { -> &'a RefCell> { &self.unboxed_closures } + + fn loop_analysis(&self) -> Option<&LoopAnalysis> { + None + } } /// The category of explicit self. @@ -5454,7 +5479,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, typ: t) { walk_ty(typ, |typ| { match get(typ).sty { - ty_rptr(region, _) => accumulator.push(region), + ty_rptr(ref region, _) => accumulator.push((*region).clone()), ty_enum(_, ref substs) | ty_trait(box TyTrait { substs: ref substs, @@ -5465,18 +5490,22 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, subst::ErasedRegions => {} subst::NonerasedRegions(ref regions) => { for region in regions.iter() { - accumulator.push(*region) + accumulator.push((*region).clone()) } } } } ty_closure(ref closure_ty) => { match closure_ty.store { - RegionTraitStore(region, _) => accumulator.push(region), + RegionTraitStore(ref region, _) => { + accumulator.push((*region).clone()) + } UniqTraitStore => {} } } - ty_unboxed_closure(_, ref region) => accumulator.push(*region), + ty_unboxed_closure(_, ref region) => { + accumulator.push((*region).clone()) + } ty_nil | ty_bot | ty_bool | diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 07c8573ef853b..2fa9151a26937 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -77,15 +77,15 @@ pub trait TypeFolder { super_fold_closure_ty(self, fty) } - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - r + fn fold_region(&mut self, r: &ty::Region) -> ty::Region { + (*r).clone() } - fn fold_trait_store(&mut self, s: ty::TraitStore) -> ty::TraitStore { + fn fold_trait_store(&mut self, s: &ty::TraitStore) -> ty::TraitStore { super_fold_trait_store(self, s) } - fn fold_existential_bounds(&mut self, s: ty::ExistentialBounds) + fn fold_existential_bounds(&mut self, s: &ty::ExistentialBounds) -> ty::ExistentialBounds { super_fold_existential_bounds(self, s) } @@ -142,7 +142,7 @@ impl TypeFoldable for VecPerParamSpace { impl TypeFoldable for ty::TraitStore { fn fold_with(&self, folder: &mut F) -> ty::TraitStore { - folder.fold_trait_store(*self) + folder.fold_trait_store(self) } } @@ -190,7 +190,7 @@ impl TypeFoldable for ty::TraitRef { impl TypeFoldable for ty::Region { fn fold_with(&self, folder: &mut F) -> ty::Region { - folder.fold_region(*self) + folder.fold_region(self) } } @@ -243,7 +243,7 @@ impl TypeFoldable for ty::BuiltinBounds { impl TypeFoldable for ty::ExistentialBounds { fn fold_with(&self, folder: &mut F) -> ty::ExistentialBounds { - folder.fold_existential_bounds(*self) + folder.fold_existential_bounds(self) } } @@ -296,7 +296,7 @@ impl TypeFoldable for ty::UnsizeKind { match *self { ty::UnsizeLength(len) => ty::UnsizeLength(len), ty::UnsizeStruct(box ref k, n) => ty::UnsizeStruct(box k.fold_with(folder), n), - ty::UnsizeVtable(bounds, def_id, ref substs) => { + ty::UnsizeVtable(ref bounds, def_id, ref substs) => { ty::UnsizeVtable(bounds.fold_with(folder), def_id, substs.fold_with(folder)) } } @@ -402,7 +402,7 @@ pub fn super_fold_sty(this: &mut T, ty::ty_trait(box ty::TyTrait { def_id, ref substs, - bounds + ref bounds }) => { ty::ty_trait(box ty::TyTrait { def_id: def_id, @@ -419,7 +419,7 @@ pub fn super_fold_sty(this: &mut T, ty::ty_closure(ref f) => { ty::ty_closure(box f.fold_with(this)) } - ty::ty_rptr(r, ref tm) => { + ty::ty_rptr(ref r, ref tm) => { ty::ty_rptr(r.fold_with(this), tm.fold_with(this)) } ty::ty_struct(did, ref substs) => { @@ -438,19 +438,20 @@ pub fn super_fold_sty(this: &mut T, } pub fn super_fold_trait_store(this: &mut T, - trait_store: ty::TraitStore) + trait_store: &ty::TraitStore) -> ty::TraitStore { - match trait_store { + match *trait_store { ty::UniqTraitStore => ty::UniqTraitStore, - ty::RegionTraitStore(r, m) => { + ty::RegionTraitStore(ref r, m) => { ty::RegionTraitStore(r.fold_with(this), m) } } } -pub fn super_fold_existential_bounds(this: &mut T, - bounds: ty::ExistentialBounds) - -> ty::ExistentialBounds { +pub fn super_fold_existential_bounds(this: &mut T, + bounds: &ty::ExistentialBounds) + -> ty::ExistentialBounds + where T: TypeFolder { ty::ExistentialBounds { region_bound: bounds.region_bound.fold_with(this), builtin_bounds: bounds.builtin_bounds, @@ -462,8 +463,10 @@ pub fn super_fold_autoref(this: &mut T, -> ty::AutoRef { match *autoref { - ty::AutoPtr(r, m, None) => ty::AutoPtr(this.fold_region(r), m, None), - ty::AutoPtr(r, m, Some(ref a)) => { + ty::AutoPtr(ref r, m, None) => { + ty::AutoPtr(this.fold_region(r), m, None) + } + ty::AutoPtr(ref r, m, Some(ref a)) => { ty::AutoPtr(this.fold_region(r), m, Some(box super_fold_autoref(this, &**a))) } ty::AutoUnsafe(m, None) => ty::AutoUnsafe(m, None), @@ -519,13 +522,13 @@ impl<'a> TypeFolder for BottomUpFolder<'a> { pub struct RegionFolder<'a> { tcx: &'a ty::ctxt, fld_t: |ty::t|: 'a -> ty::t, - fld_r: |ty::Region|: 'a -> ty::Region, + fld_r: |&ty::Region|: 'a -> ty::Region, within_binder_ids: Vec, } impl<'a> RegionFolder<'a> { pub fn general(tcx: &'a ty::ctxt, - fld_r: |ty::Region|: 'a -> ty::Region, + fld_r: |&ty::Region|: 'a -> ty::Region, fld_t: |ty::t|: 'a -> ty::t) -> RegionFolder<'a> { RegionFolder { @@ -536,7 +539,7 @@ impl<'a> RegionFolder<'a> { } } - pub fn regions(tcx: &'a ty::ctxt, fld_r: |ty::Region|: 'a -> ty::Region) + pub fn regions(tcx: &'a ty::ctxt, fld_r: |&ty::Region|: 'a -> ty::Region) -> RegionFolder<'a> { fn noop(t: ty::t) -> ty::t { t } @@ -580,11 +583,11 @@ impl<'a> TypeFolder for RegionFolder<'a> { ret } - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - match r { + fn fold_region(&mut self, r: &ty::Region) -> ty::Region { + match *r { ty::ReLateBound(binder_id, _) if self.within_binder_ids.contains(&binder_id) => { debug!("RegionFolder.fold_region({}) skipped bound region", r.repr(self.tcx())); - r + (*r).clone() } _ => { debug!("RegionFolder.fold_region({}) folding free region", r.repr(self.tcx())); diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 6cd61a8c3f85c..07fcd80492c19 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -139,7 +139,7 @@ pub fn opt_ast_region_to_region( } Ok(rs) => { - *rs.get(0) + (*rs.get(0)).clone() } } } @@ -526,7 +526,7 @@ impl PointerTy { match *self { Box => ty::ReStatic, Uniq => ty::ReStatic, - RPtr(r) => r, + RPtr(ref r) => (*r).clone(), } } } @@ -739,8 +739,12 @@ pub fn ast_ty_to_ty( ast::TyRptr(ref region, ref mt) => { let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region); debug!("ty_rptr r={}", r.repr(this.tcx())); - mk_pointer(this, rscope, mt, RPtr(r), - |ty| ty::mk_rptr(tcx, r, ty::mt {ty: ty, mutbl: mt.mutbl})) + mk_pointer(this, rscope, mt, RPtr(r.clone()), |ty| { + ty::mk_rptr(tcx, r.clone(), ty::mt { + ty: ty, + mutbl: mt.mutbl, + }) + }) } ast::TyTup(ref fields) => { let flds = fields.iter() @@ -769,9 +773,9 @@ pub fn ast_ty_to_ty( ast_ty.id, f.fn_style, f.onceness, - bounds, + &bounds, ty::RegionTraitStore( - bounds.region_bound, + bounds.region_bound.clone(), ast::MutMutable), &*f.decl, abi::Rust, @@ -790,7 +794,7 @@ pub fn ast_ty_to_ty( ast_ty.id, f.fn_style, f.onceness, - bounds, + &bounds, ty::UniqTraitStore, &*f.decl, abi::Rust, @@ -986,7 +990,8 @@ fn ty_of_method_or_bare_fn( // Figure out and record the explicit self category. let explicit_self_category = determine_explicit_self_category(this, &rb, &self_info); - explicit_self_category_result = Some(explicit_self_category); + explicit_self_category_result = + Some(explicit_self_category.clone()); match explicit_self_category { ty::StaticExplicitSelfCategory => (None, None), ty::ByValueExplicitSelfCategory => { @@ -994,7 +999,7 @@ fn ty_of_method_or_bare_fn( } ty::ByReferenceExplicitSelfCategory(region, mutability) => { (Some(ty::mk_rptr(this.tcx(), - region, + region.clone(), ty::mt { ty: self_info.untransformed_self_ty, mutbl: mutability @@ -1035,7 +1040,7 @@ fn ty_of_method_or_bare_fn( ty::accumulate_lifetimes_in_type(&mut accumulator, *input_type) } if accumulator.len() == 1 { - implied_output_region = Some(*accumulator.get(0)); + implied_output_region = Some((*accumulator.get(0)).clone()); } } @@ -1044,7 +1049,7 @@ fn ty_of_method_or_bare_fn( _ => { match implied_output_region { Some(implied_output_region) => { - let rb = SpecificRscope::new(implied_output_region); + let rb = SpecificRscope::new(&implied_output_region); ast_ty_to_ty(this, &rb, &*decl.output) } None => { @@ -1102,7 +1107,8 @@ fn determine_explicit_self_category { - inference_context.resolve_regions_and_report_errors(); + inference_context.resolve_regions_and_report_errors( + None); return ty::ByValueExplicitSelfCategory } Err(_) => {} @@ -1110,7 +1116,7 @@ fn determine_explicit_self_category { + ty::ty_rptr(ref region, tm) => { typeck::require_same_types( this.tcx(), None, @@ -1119,8 +1125,9 @@ fn determine_explicit_self_category { typeck::require_same_types( @@ -1145,18 +1152,18 @@ fn determine_explicit_self_category( - this: &AC, - id: ast::NodeId, - fn_style: ast::FnStyle, - onceness: ast::Onceness, - bounds: ty::ExistentialBounds, - store: ty::TraitStore, - decl: &ast::FnDecl, - abi: abi::Abi, - expected_sig: Option) - -> ty::ClosureTy -{ +pub fn ty_of_closure( + this: &AC, + id: ast::NodeId, + fn_style: ast::FnStyle, + onceness: ast::Onceness, + bounds: &ty::ExistentialBounds, + store: ty::TraitStore, + decl: &ast::FnDecl, + abi: abi::Abi, + expected_sig: Option) + -> ty::ClosureTy + where AC: AstConv { debug!("ty_of_fn_decl"); // new region names that appear inside of the fn decl are bound to @@ -1187,7 +1194,7 @@ pub fn ty_of_closure( fn_style: fn_style, onceness: onceness, store: store, - bounds: bounds, + bounds: (*bounds).clone(), abi: abi, sig: ty::FnSig {binder_id: id, inputs: input_tys, @@ -1320,7 +1327,7 @@ pub fn compute_opt_region_bound(tcx: &ty::ctxt, // Determine whether there is exactly one unique region in the set // of derived region bounds. If so, use that. Otherwise, report an // error. - let r = *derived_region_bounds.get(0); + let r = (*derived_region_bounds.get(0)).clone(); if derived_region_bounds.slice_from(1).iter().any(|r1| r != *r1) { tcx.sess.span_err( span, diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 77e5fbae6ee1c..f0acfd4a9d0ca 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -34,7 +34,7 @@ use syntax::print::pprust; pub fn check_match(fcx: &FnCtxt, expr: &ast::Expr, discrim: &ast::Expr, - arms: &[ast::Arm]) { + arms: &[Gc]) { let tcx = fcx.ccx.tcx; let discrim_ty = fcx.infcx().next_ty_var(); @@ -676,13 +676,15 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) { return; } }, - ty::ty_rptr(r, mt) => match ty::get(mt.ty).sty { - ty::ty_vec(ty, None) => (ty, r, mt.mutbl, None), - _ => { - check_err("a vector pattern".to_string()); - return; + ty::ty_rptr(ref r, mt) => { + match ty::get(mt.ty).sty { + ty::ty_vec(ty, None) => (ty, (*r).clone(), mt.mutbl, None), + _ => { + check_err("a vector pattern".to_string()); + return; + } } - }, + } _ => { check_err("a vector pattern".to_string()); return; diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 3c15135807b9f..58abd3b5948d4 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -239,10 +239,9 @@ fn construct_transformed_self_ty_for_object( span: Span, trait_def_id: ast::DefId, rcvr_substs: &subst::Substs, - rcvr_bounds: ty::ExistentialBounds, + rcvr_bounds: &ty::ExistentialBounds, method_ty: &ty::Method) - -> ty::t -{ + -> ty::t { /*! * This is a bit tricky. We have a match against a trait method * being invoked on an object, and we want to generate the @@ -276,21 +275,28 @@ fn construct_transformed_self_ty_for_object( tcx.sess.span_bug(span, "static method for object type receiver"); } ByValueExplicitSelfCategory => { - let tr = ty::mk_trait(tcx, trait_def_id, obj_substs, rcvr_bounds); + let tr = ty::mk_trait(tcx, + trait_def_id, + obj_substs, + (*rcvr_bounds).clone()); ty::mk_uniq(tcx, tr) } ByReferenceExplicitSelfCategory(..) | ByBoxExplicitSelfCategory => { let transformed_self_ty = *method_ty.fty.sig.inputs.get(0); match ty::get(transformed_self_ty).sty { - ty::ty_rptr(r, mt) => { // must be SelfRegion + ty::ty_rptr(ref r, mt) => { // must be SelfRegion let r = r.subst(tcx, rcvr_substs); // handle Early-Bound lifetime - let tr = ty::mk_trait(tcx, trait_def_id, obj_substs, - rcvr_bounds); + let tr = ty::mk_trait(tcx, + trait_def_id, + obj_substs, + (*rcvr_bounds).clone()); ty::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: mt.mutbl }) } ty::ty_uniq(_) => { // must be SelfUniq - let tr = ty::mk_trait(tcx, trait_def_id, obj_substs, - rcvr_bounds); + let tr = ty::mk_trait(tcx, + trait_def_id, + obj_substs, + (*rcvr_bounds).clone()); ty::mk_uniq(tcx, tr) } _ => { @@ -441,9 +447,15 @@ impl<'a> LookupContext<'a> { let span = self.self_expr.map_or(self.span, |e| e.span); check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| { match get(self_ty).sty { - ty_trait(box TyTrait { def_id, ref substs, bounds, .. }) => { - self.push_inherent_candidates_from_object( - def_id, substs, bounds); + ty_trait(box TyTrait { + def_id, + ref substs, + ref bounds, + .. + }) => { + self.push_inherent_candidates_from_object(def_id, + substs, + bounds); self.push_inherent_impl_candidates_for_type(def_id); } ty_enum(did, _) | @@ -594,7 +606,7 @@ impl<'a> LookupContext<'a> { fn push_inherent_candidates_from_object(&mut self, did: DefId, substs: &subst::Substs, - bounds: ty::ExistentialBounds) { + bounds: &ty::ExistentialBounds) { debug!("push_inherent_candidates_from_object(did={}, substs={})", self.did_to_string(did), substs.repr(self.tcx())); @@ -902,7 +914,7 @@ impl<'a> LookupContext<'a> { ty::ty_rptr(_, self_mt) => { let region = self.infcx().next_region_var(infer::Autoref(self.span)); - (ty::mk_rptr(tcx, region, self_mt), + (ty::mk_rptr(tcx, region.clone(), self_mt), ty::AutoDerefRef { autoderefs: autoderefs + 1, autoref: Some(ty::AutoPtr(region, self_mt.mutbl, None))}) @@ -936,8 +948,12 @@ impl<'a> LookupContext<'a> { // First try to borrow to a slice let entry = self.search_for_some_kind_of_autorefd_method( |r, m| AutoPtr(r, m, None), autoderefs, [MutImmutable, MutMutable], - |m,r| ty::mk_slice(tcx, r, - ty::mt {ty:ty, mutbl:m})); + |m, r| { + ty::mk_slice(tcx, (*r).clone(), ty::mt { + ty: ty, + mutbl: m, + }) + }); if entry.is_some() { return entry; @@ -945,17 +961,26 @@ impl<'a> LookupContext<'a> { // Then try to borrow to a slice *and* borrow a pointer. self.search_for_some_kind_of_autorefd_method( - |r, m| AutoPtr(r, ast::MutImmutable, Some( box AutoPtr(r, m, None))), + |r, m| { + AutoPtr(r.clone(), + ast::MutImmutable, + Some(box AutoPtr(r, m, None))) + }, autoderefs, [MutImmutable, MutMutable], |m, r| { - let slice_ty = ty::mk_slice(tcx, r, - ty::mt {ty:ty, mutbl:m}); + let slice_ty = ty::mk_slice(tcx, (*r).clone(), ty::mt { + ty: ty, + mutbl: m, + }); // NB: we do not try to autoref to a mutable // pointer. That would be creating a pointer // to a temporary pointer (the borrowed // slice), so any update the callee makes to // it can't be observed. - ty::mk_rptr(tcx, r, ty::mt {ty:slice_ty, mutbl:MutImmutable}) + ty::mk_rptr(tcx, (*r).clone(), ty::mt { + ty: slice_ty, + mutbl: MutImmutable, + }) }) } @@ -978,7 +1003,12 @@ impl<'a> LookupContext<'a> { let entry = self.search_for_some_kind_of_autorefd_method( |r, m| AutoPtr(r, m, Some(box AutoUnsize(ty::UnsizeLength(len)))), autoderefs, [MutImmutable, MutMutable], - |m, r| ty::mk_slice(tcx, r, ty::mt {ty:ty, mutbl:m})); + |m, r| { + ty::mk_slice(tcx, (*r).clone(), ty::mt { + ty: ty, + mutbl: m, + }) + }); if entry.is_some() { return entry; @@ -986,13 +1016,25 @@ impl<'a> LookupContext<'a> { // Then try to borrow to a slice *and* borrow a pointer. self.search_for_some_kind_of_autorefd_method( - |r, m| AutoPtr(r, m, - Some(box AutoPtr(r, m, - Some(box AutoUnsize(ty::UnsizeLength(len)))))), - autoderefs, [MutImmutable, MutMutable], + |r, m| { + AutoPtr(r.clone(), + m, + Some(box AutoPtr( + r.clone(), + m, + Some(box AutoUnsize(ty::UnsizeLength(len)))))) + }, + autoderefs, + [MutImmutable, MutMutable], |m, r| { - let slice_ty = ty::mk_slice(tcx, r, ty::mt {ty:ty, mutbl:m}); - ty::mk_rptr(tcx, r, ty::mt {ty:slice_ty, mutbl:MutImmutable}) + let slice_ty = ty::mk_slice(tcx, (*r).clone(), ty::mt { + ty: ty, + mutbl: m, + }); + ty::mk_rptr(tcx, (*r).clone(), ty::mt { + ty: slice_ty, + mutbl: MutImmutable, + }) }) } @@ -1002,18 +1044,26 @@ impl<'a> LookupContext<'a> { let entry = self.search_for_some_kind_of_autorefd_method( |r, m| AutoPtr(r, m, None), autoderefs, [MutImmutable], - |_m, r| ty::mk_str_slice(tcx, r, MutImmutable)); + |_m, r| ty::mk_str_slice(tcx, (*r).clone(), MutImmutable)); if entry.is_some() { return entry; } self.search_for_some_kind_of_autorefd_method( - |r, m| AutoPtr(r, ast::MutImmutable, Some( box AutoPtr(r, m, None))), - autoderefs, [MutImmutable], + |r, m| { + AutoPtr(r.clone(), + ast::MutImmutable, + Some(box AutoPtr(r, m, None))) + }, + autoderefs, + [MutImmutable], |m, r| { - let slice_ty = ty::mk_str_slice(tcx, r, m); - ty::mk_rptr(tcx, r, ty::mt {ty:slice_ty, mutbl:m}) + let slice_ty = ty::mk_str_slice(tcx, r.clone(), m); + ty::mk_rptr(tcx, (*r).clone(), ty::mt { + ty: slice_ty, + mutbl: m, + }) }) } @@ -1024,15 +1074,21 @@ impl<'a> LookupContext<'a> { ty_trait(box ty::TyTrait { def_id: trt_did, substs: ref trt_substs, - bounds: b, + bounds: ref b, .. }) => { let tcx = self.tcx(); self.search_for_some_kind_of_autorefd_method( |r, m| AutoPtr(r, m, None), autoderefs, [MutImmutable, MutMutable], |m, r| { - let tr = ty::mk_trait(tcx, trt_did, trt_substs.clone(), b); - ty::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: m }) + let tr = ty::mk_trait(tcx, + trt_did, + trt_substs.clone(), + (*b).clone()); + ty::mk_rptr(tcx, (*r).clone(), ty::mt { + ty: tr, + mutbl: m, + }) }) } _ => fail!("Expected ty_trait in auto_slice_trait") @@ -1088,7 +1144,12 @@ impl<'a> LookupContext<'a> { ty_str | ty_vec(..) | ty_trait(..) | ty_closure(..) => { self.search_for_some_kind_of_autorefd_method( |r, m| AutoPtr(r, m, None), autoderefs, [MutImmutable, MutMutable], - |m,r| ty::mk_rptr(tcx, r, ty::mt {ty:self_ty, mutbl:m})) + |m, r| { + ty::mk_rptr(tcx, (*r).clone(), ty::mt { + ty: self_ty, + mutbl: m, + }) + }) } ty_err => None, @@ -1105,7 +1166,7 @@ impl<'a> LookupContext<'a> { kind: |Region, ast::Mutability| -> ty::AutoRef, autoderefs: uint, mutbls: &[ast::Mutability], - mk_autoref_ty: |ast::Mutability, ty::Region| -> ty::t) + mk_autoref_ty: |ast::Mutability, &ty::Region| -> ty::t) -> Option { // Hacky. For overloaded derefs, there may be an adjustment // added to the expression from the outside context, so we do not store @@ -1126,7 +1187,7 @@ impl<'a> LookupContext<'a> { let region = self.infcx().next_region_var(infer::Autoref(self.span)); for mutbl in mutbls.iter() { - let autoref_ty = mk_autoref_ty(*mutbl, region); + let autoref_ty = mk_autoref_ty(*mutbl, ®ion); match self.search_for_method(autoref_ty) { None => {} Some(method) => { diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index c70e85051749c..b50b13747211b 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -81,6 +81,7 @@ use middle::const_eval; use middle::def; use middle::freevars; use middle::lang_items::IteratorItem; +use middle::loop_analysis::{LoopAnalysis, LoopAnalyzer}; use middle::mem_categorization::McResult; use middle::mem_categorization; use middle::pat_util::pat_id_map; @@ -205,12 +206,17 @@ pub struct Inherited<'a> { region_obligations: RefCell>>, } -struct RegionObligation { - sub_region: ty::Region, +pub struct RegionObligation { + sub_region: RegionObligationRegion, sup_type: ty::t, origin: infer::SubregionOrigin, } +pub enum RegionObligationRegion { + RegionObligationRegion(ty::Region), + RegionObligationScope(ast::NodeId), +} + /// When type-checking an expression, we propagate downward /// whatever type hint we are able in the form of an `Expectation`. enum Expectation { @@ -320,6 +326,9 @@ impl<'a> mem_categorization::Typer for FnCtxt<'a> { -> &'a RefCell> { &self.inh.unboxed_closures } + fn loop_analysis(&self) -> Option<&LoopAnalysis> { + None + } } impl<'a> Inherited<'a> { @@ -367,7 +376,7 @@ fn static_inherited_fields<'a>(ccx: &'a CrateCtxt<'a>) -> Inherited<'a> { let param_env = ty::ParameterEnvironment { free_substs: subst::Substs::empty(), bounds: subst::VecPerParamSpace::empty(), - implicit_region_bound: ty::ReStatic, + implicit_region_bound: ty::RegionImplicitRegionBound(ty::ReStatic), }; Inherited::new(ccx.tcx, param_env) } @@ -443,7 +452,10 @@ fn check_bare_fn(ccx: &CrateCtxt, decl, id, body, &inh); vtable::resolve_in_block(&fcx, body); - regionck::regionck_fn(&fcx, id, body); + + let loop_analysis = + LoopAnalyzer::new(ccx.tcx).analyze_block(body); + regionck::regionck_fn(&fcx, loop_analysis, id, body); writeback::resolve_type_vars_in_fn(&fcx, decl, body); } _ => ccx.tcx.sess.impossible_case(body.span, @@ -770,8 +782,7 @@ fn check_type_well_formed(ccx: &CrateCtxt, item: &ast::Item) { fn check_type_defn(ccx: &CrateCtxt, item: &ast::Item, - lookup_fields: |&FnCtxt| -> Vec) - { + lookup_fields: |&FnCtxt| -> Vec) { let item_def_id = local_def(item.id); let polytype = ty::lookup_item_type(ccx.tcx, item_def_id); let param_env = @@ -1260,13 +1271,12 @@ fn compare_impl_method(tcx: &ty::ctxt, "method `{}` has an incompatible type for trait: {}", token::get_ident(trait_m.ident), ty::type_err_to_str(tcx, terr)); - ty::note_and_explain_type_err(tcx, terr); } } // Finally, resolve all regions. This catches wily misuses of lifetime // parameters. - infcx.resolve_regions_and_report_errors(); + infcx.resolve_regions_and_report_errors(None); fn check_region_bounds_on_impl_method(tcx: &ty::ctxt, span: Span, @@ -1275,8 +1285,7 @@ fn compare_impl_method(tcx: &ty::ctxt, impl_generics: &ty::Generics, trait_to_skol_substs: &Substs, impl_to_skol_substs: &Substs) - -> bool - { + -> bool { /*! Check that region bounds on impl method are the same as those @@ -1364,14 +1373,14 @@ fn compare_impl_method(tcx: &ty::ctxt, let missing: Vec = trait_bounds.iter() .filter(|&b| !impl_bounds.contains(b)) - .map(|&b| b) + .map(|b| (*b).clone()) .collect(); // Collect set present in impl but not in trait. let extra: Vec = impl_bounds.iter() .filter(|&b| !trait_bounds.contains(b)) - .map(|&b| b) + .map(|b| (*b).clone()) .collect(); debug!("missing={} extra={}", @@ -1761,7 +1770,7 @@ impl<'a> FnCtxt<'a> { sub, sup) { Ok(None) => Ok(()), - Err(ref e) => Err((*e)), + Err(ref e) => Err((*e).clone()), Ok(Some(adjustment)) => { self.write_adjustment(expr.id, adjustment); Ok(()) @@ -1780,8 +1789,8 @@ impl<'a> FnCtxt<'a> { pub fn mk_subr(&self, origin: infer::SubregionOrigin, - sub: ty::Region, - sup: ty::Region) { + sub: &ty::Region, + sup: &ty::Region) { infer::mk_subr(self.infcx(), origin, sub, sup) } @@ -1816,8 +1825,7 @@ impl<'a> FnCtxt<'a> { pub fn register_region_obligation(&self, origin: infer::SubregionOrigin, ty: ty::t, - r: ty::Region) - { + r: RegionObligationRegion) { /*! * Registers an obligation for checking later, during * regionck, that the type `ty` must outlive the region `r`. @@ -1826,9 +1834,11 @@ impl<'a> FnCtxt<'a> { let mut region_obligations = self.inh.region_obligations.borrow_mut(); let v = region_obligations.find_or_insert_with(self.body_id, |_| Vec::new()); - v.push(RegionObligation { sub_region: r, - sup_type: ty, - origin: origin }); + v.push(RegionObligation { + sub_region: r, + sup_type: ty, + origin: origin, + }); } pub fn add_region_obligations_for_parameters(&self, @@ -1875,7 +1885,7 @@ impl<'a> FnCtxt<'a> { assert_eq!(generics.regions.iter().len(), substs.regions().iter().len()); - for (region_def, ®ion_param) in + for (region_def, region_param) in generics.regions.iter().zip( substs.regions().iter()) { @@ -1889,8 +1899,7 @@ impl<'a> FnCtxt<'a> { span: Span, param_ty: ty::ParamTy, param_bound: &ty::ParamBounds, - ty: ty::t) - { + ty: ty::t) { // For each declared region bound `T:r`, `T` must outlive `r`. let region_bounds = ty::required_region_bounds( @@ -1898,9 +1907,12 @@ impl<'a> FnCtxt<'a> { param_bound.opt_region_bound.as_slice(), param_bound.builtin_bounds, param_bound.trait_bounds.as_slice()); - for &r in region_bounds.iter() { + for r in region_bounds.iter() { let origin = infer::RelateParamBound(span, param_ty, ty); - fcx.register_region_obligation(origin, ty, r); + fcx.register_region_obligation( + origin, + ty, + RegionObligationRegion((*r).clone())); } } @@ -1908,9 +1920,8 @@ impl<'a> FnCtxt<'a> { fcx: &FnCtxt, span: Span, region_bounds: &[ty::Region], - region_param: ty::Region) - { - for &b in region_bounds.iter() { + region_param: &ty::Region) { + for b in region_bounds.iter() { // For each bound `region:b`, `b <= region` must hold // (i.e., `region` must outlive `b`). let origin = infer::RelateRegionParamBound(span); @@ -3074,7 +3085,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, // are lies, but we ignore them so it doesn't matter. // // FIXME(pcwalton): Refactor this API. - ty::region_existential_bound(ty::ReStatic), + &ty::region_existential_bound(ty::ReStatic), ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable), decl, @@ -3086,7 +3097,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, fcx.ccx.tcx.sess.span_bug(expr.span, "can't make anon regions here?!") } - Ok(regions) => *regions.get(0), + Ok(regions) => (*regions.get(0)).clone(), }; let closure_type = ty::mk_unboxed_closure(fcx.ccx.tcx, local_def(expr.id), @@ -3165,7 +3176,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, (&ty::UniqTraitStore, _) => ast::Once, (&ty::RegionTraitStore(..), _) => ast::Many, }; - (Some(sig), onceness, cenv.bounds) + (Some(sig), onceness, cenv.bounds.clone()) } _ => { // Not an error! Means we're inferring the closure type @@ -3181,7 +3192,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, (ty::region_existential_bound(region), ast::Many) } }; - (None, onceness, bounds) + (None, onceness, bounds.clone()) } } }; @@ -3191,7 +3202,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, expr.id, ast::NormalFn, expected_onceness, - expected_bounds, + &expected_bounds, store, decl, abi::Rust, @@ -3499,9 +3510,10 @@ fn check_expr_with_unifier(fcx: &FnCtxt, fcx.write_ty(id, ty::mk_uniq(tcx, referent_ty)); checked = true } else if tcx.lang_items.managed_heap() == Some(def_id) { - fcx.register_region_obligation(infer::Managed(expr.span), - referent_ty, - ty::ReStatic); + fcx.register_region_obligation( + infer::Managed(expr.span), + referent_ty, + RegionObligationRegion(ty::ReStatic)); fcx.write_ty(id, ty::mk_box(tcx, referent_ty)); checked = true } @@ -4067,7 +4079,6 @@ fn check_expr_with_unifier(fcx: &FnCtxt, .ty_to_string( actual_structure_type), type_error_description).as_slice()); - ty::note_and_explain_type_err(tcx, &type_error); } } } @@ -4137,12 +4148,10 @@ fn check_expr_with_unifier(fcx: &FnCtxt, unifier(); } -fn constrain_path_type_parameters(fcx: &FnCtxt, - expr: &ast::Expr) -{ +fn constrain_path_type_parameters(fcx: &FnCtxt, expr: &ast::Expr) { fcx.opt_node_ty_substs(expr.id, |item_substs| { for &ty in item_substs.substs.types.iter() { - let default_bound = ty::ReScope(expr.id); + let default_bound = RegionObligationScope(expr.id); let origin = infer::RelateDefaultParamBound(expr.span, ty); fcx.register_region_obligation(origin, ty, default_bound); } @@ -4447,6 +4456,7 @@ pub fn check_const_with_ty(fcx: &FnCtxt, check_expr_with_hint(fcx, e, declty); demand::coerce(fcx, e.span, declty, e); + regionck::regionck_expr(fcx, e); writeback::resolve_type_vars_in_expr(fcx, e); } @@ -5549,3 +5559,13 @@ impl Repr for RegionObligation { self.origin.repr(tcx)) } } + +impl Repr for RegionObligationRegion { + fn repr(&self, tcx: &ty::ctxt) -> String { + match *self { + RegionObligationRegion(ref region) => region.repr(tcx), + RegionObligationScope(scope_id) => format!("Scope({})", scope_id), + } + } +} + diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 16ecaa9714ec7..f207eb2e026b4 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -121,11 +121,16 @@ and report an error, and it just seems like more mess in the end.) use middle::def; use middle::def::{DefArg, DefBinding, DefLocal, DefUpvar}; use middle::freevars; +use middle::loop_analysis::{LoopAnalysis, LoopAnalyzer}; use middle::mem_categorization as mc; -use middle::ty::{ReScope}; +use middle::mem_categorization::Typer; +use middle::region; +use middle::seme_region::SemeRegion; +use middle::ty::ReSemeRegion; use middle::ty; use middle::typeck::astconv::AstConv; -use middle::typeck::check::FnCtxt; +use middle::typeck::check::{FnCtxt, RegionObligationRegion}; +use middle::typeck::check::{RegionObligationScope}; use middle::typeck::check::regionmanip; use middle::typeck::infer::resolve_and_force_all_but_regions; use middle::typeck::infer::resolve_type; @@ -147,37 +152,44 @@ use std::gc::Gc; // PUBLIC ENTRY POINTS pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) { - let mut rcx = Rcx::new(fcx, e.id); + let loop_analysis = LoopAnalyzer::new(fcx.tcx()).analyze_expr(e); + let mut rcx = Rcx::new(fcx, Some(loop_analysis), e.id); if fcx.err_count_since_creation() == 0 { // regionck assumes typeck succeeded rcx.visit_expr(e, ()); rcx.visit_region_obligations(e.id); } - fcx.infcx().resolve_regions_and_report_errors(); + fcx.infcx().resolve_regions_and_report_errors(rcx.loop_analysis()); } pub fn regionck_type_defn(fcx: &FnCtxt, span: Span, component_tys: &[ty::t]) { - let mut rcx = Rcx::new(fcx, 0); + let mut rcx = Rcx::new(fcx, None, 0); for &component_ty in component_tys.iter() { // Check that each type outlives the empty region. Since the // empty region is a subregion of all others, this can't fail // unless the type does not meet the well-formedness // requirements. - type_must_outlive(&mut rcx, infer::RelateRegionParamBound(span), - component_ty, ty::ReEmpty); + type_must_outlive(&mut rcx, + infer::RelateRegionParamBound(span), + component_ty, + &ty::ReEmpty); } - fcx.infcx().resolve_regions_and_report_errors(); + fcx.infcx().resolve_regions_and_report_errors(rcx.loop_analysis()); } -pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, blk: &ast::Block) { - let mut rcx = Rcx::new(fcx, blk.id); +pub fn regionck_fn<'a>( + fcx: &'a FnCtxt<'a>, + loop_analysis: LoopAnalysis, + id: ast::NodeId, + blk: &ast::Block) { + let mut rcx = Rcx::new(fcx, Some(loop_analysis), blk.id); if fcx.err_count_since_creation() == 0 { // regionck assumes typeck succeeded rcx.visit_fn_body(id, blk); } - fcx.infcx().resolve_regions_and_report_errors(); + fcx.infcx().resolve_regions_and_report_errors(rcx.loop_analysis()); } /////////////////////////////////////////////////////////////////////////// @@ -198,6 +210,7 @@ macro_rules! ignore_err( pub struct Rcx<'a> { fcx: &'a FnCtxt<'a>, + loop_analysis: Option, region_param_pairs: Vec<(ty::Region, ty::ParamTy)>, @@ -225,7 +238,10 @@ pub struct RegionSubParamConstraints<'a> { previous: Option<&'a RegionSubParamConstraints<'a>>, } -fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region { +fn region_of_def(fcx: &FnCtxt, + loop_analysis: Option<&LoopAnalysis>, + def: def::Def) + -> ty::Region { /*! * Returns the validity region of `def` -- that is, how long * is `def` valid? @@ -235,12 +251,26 @@ fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region { match def { DefLocal(node_id, _) | DefArg(node_id, _) | DefBinding(node_id, _) => { - tcx.region_maps.var_region(node_id) + tcx.region_maps.var_region(fcx.tcx(), loop_analysis, node_id) } DefUpvar(_, subdef, closure_id, body_id) => { match ty::ty_closure_store(fcx.node_ty(closure_id)) { - ty::RegionTraitStore(..) => region_of_def(fcx, *subdef), - ty::UniqTraitStore => ReScope(body_id) + ty::RegionTraitStore(..) => { + region_of_def(fcx, loop_analysis, *subdef) + } + ty::UniqTraitStore => { + match loop_analysis { + None => { + tcx.sess.bug("region_of_def(): unique trait \ + store in non-fn?!") + } + Some(loop_analysis) => { + ReSemeRegion(SemeRegion::from_scope(tcx, + loop_analysis, + body_id)) + } + } + } } } _ => { @@ -252,10 +282,15 @@ fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region { impl<'a> Rcx<'a> { pub fn new(fcx: &'a FnCtxt<'a>, - initial_repeating_scope: ast::NodeId) -> Rcx<'a> { - Rcx { fcx: fcx, - repeating_scope: initial_repeating_scope, - region_param_pairs: Vec::new() } + loop_analysis: Option, + initial_repeating_scope: ast::NodeId) + -> Rcx<'a> { + Rcx { + fcx: fcx, + loop_analysis: loop_analysis, + repeating_scope: initial_repeating_scope, + region_param_pairs: Vec::new() + } } pub fn tcx(&self) -> &'a ty::ctxt { @@ -351,8 +386,7 @@ impl<'a> Rcx<'a> { self.region_param_pairs.truncate(len); } - fn visit_region_obligations(&mut self, node_id: ast::NodeId) - { + fn visit_region_obligations(&mut self, node_id: ast::NodeId) { debug!("visit_region_obligations: node_id={}", node_id); let region_obligations = self.fcx.inh.region_obligations.borrow(); match region_obligations.find(&node_id) { @@ -362,8 +396,21 @@ impl<'a> Rcx<'a> { debug!("visit_region_obligations: r_o={}", r_o.repr(self.tcx())); let sup_type = self.resolve_type(r_o.sup_type); - type_must_outlive(self, r_o.origin.clone(), - sup_type, r_o.sub_region); + match r_o.sub_region { + RegionObligationRegion(ref sub_region) => { + type_must_outlive(self, + r_o.origin.clone(), + sup_type, + sub_region); + } + RegionObligationScope(scope_id) => { + let sub_region = self.scope_region(scope_id); + type_must_outlive(self, + r_o.origin.clone(), + sup_type, + &sub_region); + } + } } } } @@ -394,12 +441,12 @@ impl<'a> Rcx<'a> { for &ty in fn_sig_tys.iter() { let ty = self.resolve_type(ty); debug!("relate_free_regions(t={})", ty.repr(tcx)); - let body_scope = ty::ReScope(body_id); + let body_scope = self.scope_region(body_id); let constraints = regionmanip::region_wf_constraints( tcx, ty, - body_scope); + &body_scope); for constraint in constraints.iter() { debug!("constraint: {}", constraint.repr(tcx)); match *constraint { @@ -424,11 +471,13 @@ impl<'a> Rcx<'a> { // relationship that arises here, but // presently we do not.) } - regionmanip::RegionSubParamConstraint(_, r_a, p_b) => { + regionmanip::RegionSubParamConstraint(_, + ref r_a, + p_b) => { debug!("RegionSubParamConstraint: {} <= {}", r_a.repr(tcx), p_b.repr(tcx)); - self.region_param_pairs.push((r_a, p_b)); + self.region_param_pairs.push(((*r_a).clone(), p_b)); } } } @@ -436,10 +485,14 @@ impl<'a> Rcx<'a> { debug!("<< relate_free_regions"); } + + fn scope_region(&self, id: ast::NodeId) -> ty::Region { + region::scope_region(self.tcx(), self.loop_analysis(), id) + } } impl<'fcx> mc::Typer for Rcx<'fcx> { - fn tcx<'a>(&'a self) -> &'a ty::ctxt { + fn tcx(&self) -> &ty::ctxt { self.fcx.ccx.tcx } @@ -452,7 +505,7 @@ impl<'fcx> mc::Typer for Rcx<'fcx> { self.resolve_method_type(method_call) } - fn adjustments<'a>(&'a self) -> &'a RefCell> { + fn adjustments(&self) -> &RefCell> { &self.fcx.inh.adjustments } @@ -473,10 +526,16 @@ impl<'fcx> mc::Typer for Rcx<'fcx> { self.tcx().capture_modes.borrow().get_copy(&closure_expr_id) } - fn unboxed_closures<'a>(&'a self) - -> &'a RefCell> { + fn unboxed_closures(&self) -> &RefCell> { &self.fcx.inh.unboxed_closures } + + fn loop_analysis<'a>(&'a self) -> Option<&'a LoopAnalysis> { + match self.loop_analysis { + None => None, + Some(ref loop_analysis) => Some(loop_analysis), + } + } } impl<'a> Visitor<()> for Rcx<'a> { @@ -557,10 +616,16 @@ fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) { // that the lifetime of any regions that appear in a // variable's type enclose at least the variable's scope. - let var_region = tcx.region_maps.var_region(id); - type_of_node_must_outlive( - rcx, infer::BindingTypeIsNotValidAtDecl(span), - id, var_region); + let var_region = tcx.region_maps.var_region(tcx, + rcx.loop_analysis(), + id); + debug!("var_region({}) = {}", + tcx.map.node_to_string(id), + var_region.repr(tcx)); + type_of_node_must_outlive(rcx, + infer::BindingTypeIsNotValidAtDecl(span), + id, + &var_region); }) } @@ -572,8 +637,11 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { // scope of that expression. This also guarantees basic WF. let expr_ty = rcx.resolve_node_type(expr.id); - type_must_outlive(rcx, infer::ExprTypeIsNotInScope(expr_ty, expr.span), - expr_ty, ty::ReScope(expr.id)); + let scope_region = rcx.scope_region(expr.id); + type_must_outlive(rcx, + infer::ExprTypeIsNotInScope(expr_ty, expr.span), + expr_ty, + &scope_region); let method_call = MethodCall::expr(expr.id); let has_method_map = rcx.fcx.inh.method_map.borrow().contains_key(&method_call); @@ -592,9 +660,11 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { // the current node. // // FIXME(#6268) remove to support nested method calls - type_of_node_must_outlive( - rcx, infer::AutoBorrow(expr.span), - expr.id, ty::ReScope(expr.id)); + let region = rcx.scope_region(expr.id); + type_of_node_must_outlive(rcx, + infer::AutoBorrow(expr.span), + expr.id, + ®ion); } } /* @@ -673,8 +743,10 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { ast::ExprUnary(ast::UnBox, ref base) => { // Managed data must not have borrowed pointers within it: let base_ty = rcx.resolve_node_type(base.id); - type_must_outlive(rcx, infer::Managed(expr.span), - base_ty, ty::ReStatic); + type_must_outlive(rcx, + infer::Managed(expr.span), + base_ty, + &ty::ReStatic); visit::walk_expr(rcx, expr, ()); } @@ -689,9 +761,12 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { None => rcx.resolve_node_type(base.id) }; match ty::get(base_ty).sty { - ty::ty_rptr(r_ptr, _) => { - mk_subregion_due_to_dereference(rcx, expr.span, - ty::ReScope(expr.id), r_ptr); + ty::ty_rptr(ref r_ptr, _) => { + let region = rcx.scope_region(expr.id); + mk_subregion_due_to_dereference(rcx, + expr.span, + ®ion, + r_ptr); } _ => {} } @@ -726,8 +801,11 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { // // FIXME(#6268) nested method calls requires that this rule change let ty0 = rcx.resolve_node_type(expr.id); - type_must_outlive(rcx, infer::AddrOf(expr.span), - ty0, ty::ReScope(expr.id)); + let scope_region = rcx.scope_region(expr.id); + type_must_outlive(rcx, + infer::AddrOf(expr.span), + ty0, + &scope_region); visit::walk_expr(rcx, expr, ()); } @@ -802,19 +880,23 @@ fn constrain_cast(rcx: &mut Rcx, from_ty.repr(rcx.tcx()), to_ty.repr(rcx.tcx())); match (&ty::get(from_ty).sty, &ty::get(to_ty).sty) { - /*From:*/ (&ty::ty_rptr(from_r, ref from_mt), - /*To: */ &ty::ty_rptr(to_r, ref to_mt)) => { + /*From:*/ (&ty::ty_rptr(ref from_r, ref from_mt), + /*To: */ &ty::ty_rptr(ref to_r, ref to_mt)) => { // Target cannot outlive source, naturally. - rcx.fcx.mk_subr(infer::Reborrow(cast_expr.span), to_r, from_r); + rcx.fcx.mk_subr(infer::Reborrow(cast_expr.span), + to_r, + from_r); walk_cast(rcx, cast_expr, from_mt.ty, to_mt.ty); } /*From:*/ (_, - /*To: */ &ty::ty_trait(box ty::TyTrait { bounds, .. })) => { + /*To: */ &ty::ty_trait(box ty::TyTrait { ref bounds, .. })) => { // When T is existentially quantified as a trait // `Foo+'to`, it must outlive the region bound `'to`. - type_must_outlive(rcx, infer::RelateObjectBound(cast_expr.span), - from_ty, bounds.region_bound); + type_must_outlive(rcx, + infer::RelateObjectBound(cast_expr.span), + from_ty, + &bounds.region_bound); } /*From:*/ (&ty::ty_uniq(from_referent_ty), @@ -847,13 +929,17 @@ fn check_expr_fn_block(rcx: &mut Rcx, } else { // Variables being referenced must outlive closure. constrain_free_variables_in_stack_closure( - rcx, bounds.region_bound, expr, freevars); + rcx, + &bounds.region_bound, + expr, + freevars); // Closure is stack allocated and hence cannot // outlive the appropriate temporary scope. let s = rcx.repeating_scope; rcx.fcx.mk_subr(infer::InfStackClosure(expr.span), - bounds.region_bound, ty::ReScope(s)); + &bounds.region_bound, + &rcx.scope_region(s)); } }); } @@ -864,10 +950,13 @@ fn check_expr_fn_block(rcx: &mut Rcx, // outlive region bound, since they are captured by value. freevars::with_freevars(tcx, expr.id, |freevars| { ensure_free_variable_types_outlive_closure_bound( - rcx, bounds.region_bound, expr, freevars); + rcx, + &bounds.region_bound, + expr, + freevars); }); } - ty::ty_unboxed_closure(_, region) => { + ty::ty_unboxed_closure(_, ref region) => { freevars::with_freevars(tcx, expr.id, |freevars| { // No free variables means that there is no environment and // hence the closure has static lifetime. Otherwise, the @@ -878,7 +967,10 @@ fn check_expr_fn_block(rcx: &mut Rcx, // be straightforward enough. if !freevars.is_empty() { ensure_free_variable_types_outlive_closure_bound( - rcx, region, expr, freevars); + rcx, + region, + expr, + freevars); } }) } @@ -903,10 +995,9 @@ fn check_expr_fn_block(rcx: &mut Rcx, fn ensure_free_variable_types_outlive_closure_bound( rcx: &mut Rcx, - region_bound: ty::Region, + region_bound: &ty::Region, expr: &ast::Expr, - freevars: &[freevars::freevar_entry]) - { + freevars: &[freevars::freevar_entry]) { /*! * Make sure that the type of all free variables referenced * inside a closure/proc outlive the closure/proc's lifetime @@ -936,7 +1027,7 @@ fn check_expr_fn_block(rcx: &mut Rcx, fn constrain_free_variables_in_stack_closure( rcx: &mut Rcx, - region_bound: ty::Region, + region_bound: &ty::Region, expr: &ast::Expr, freevars: &[freevars::freevar_entry]) { @@ -968,21 +1059,27 @@ fn check_expr_fn_block(rcx: &mut Rcx, let origin = infer::UpvarRegion(upvar_id, expr.span); let freevar_region = infcx.next_region_var(origin); rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id), - region_bound, freevar_region); + region_bound, + &freevar_region); // Create a UpvarBorrow entry. Note that we begin with a // const borrow_kind, but change it to either mut or // immutable as dictated by the uses. - let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, - region: freevar_region }; + let upvar_borrow = ty::UpvarBorrow { + kind: ty::ImmBorrow, + region: freevar_region + }; rcx.fcx.inh.upvar_borrow_map.borrow_mut().insert(upvar_id, upvar_borrow); // Guarantee that the closure does not outlive the variable itself. - let enclosing_region = region_of_def(rcx.fcx, def); + let enclosing_region = region_of_def(rcx.fcx, + rcx.loop_analysis(), + def); debug!("enclosing_region = {}", enclosing_region.repr(tcx)); rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id), - region_bound, enclosing_region); + region_bound, + &enclosing_region); } } @@ -1040,26 +1137,29 @@ fn constrain_callee(rcx: &mut Rcx, callee_id: ast::NodeId, call_expr: &ast::Expr, callee_expr: &ast::Expr) { - let call_region = ty::ReScope(call_expr.id); - + let call_region = rcx.scope_region(call_expr.id); let callee_ty = rcx.resolve_node_type(callee_id); match ty::get(callee_ty).sty { ty::ty_bare_fn(..) => { } ty::ty_closure(ref closure_ty) => { let region = match closure_ty.store { - ty::RegionTraitStore(r, _) => { + ty::RegionTraitStore(ref r, _) => { // While we're here, link the closure's region with a unique // immutable borrow (gathered later in borrowck) let mc = mc::MemCategorizationContext::new(rcx); let expr_cmt = ignore_err!(mc.cat_expr(callee_expr)); - link_region(rcx, callee_expr.span, call_region, - ty::UniqueImmBorrow, expr_cmt); - r + link_region(rcx, + callee_expr.span, + &call_region, + ty::UniqueImmBorrow, + expr_cmt); + (*r).clone() } ty::UniqTraitStore => ty::ReStatic }; rcx.fcx.mk_subr(infer::InvokeClosure(callee_expr.span), - call_region, region); + &call_region, + ®ion); } _ => { // this should not happen, but it does if the program is @@ -1097,7 +1197,7 @@ fn constrain_call(rcx: &mut Rcx, // // FIXME(#6268) to support nested method calls, should be callee_id let callee_scope = call_expr.id; - let callee_region = ty::ReScope(callee_scope); + let callee_region = rcx.scope_region(callee_scope); debug!("callee_region={}", callee_region.repr(tcx)); @@ -1107,8 +1207,10 @@ fn constrain_call(rcx: &mut Rcx, // ensure that any regions appearing in the argument type are // valid for at least the lifetime of the function: type_of_node_must_outlive( - rcx, infer::CallArg(arg_expr.span), - arg_expr.id, callee_region); + rcx, + infer::CallArg(arg_expr.span), + arg_expr.id, + &callee_region); // unfortunately, there are two means of taking implicit // references, and we need to propagate constraints as a @@ -1123,8 +1225,10 @@ fn constrain_call(rcx: &mut Rcx, for r in receiver.iter() { debug!("receiver: {}", r.repr(tcx)); type_of_node_must_outlive( - rcx, infer::CallRcvr(r.span), - r.id, callee_region); + rcx, + infer::CallRcvr(r.span), + r.id, + &callee_region); if implicitly_ref_args { link_by_ref(rcx, &**r, callee_scope); } @@ -1140,7 +1244,7 @@ fn constrain_autoderefs(rcx: &mut Rcx, * this is a region pointer being dereferenced, the lifetime of * the pointer includes the deref expr. */ - let r_deref_expr = ty::ReScope(deref_expr.id); + let r_deref_expr = rcx.scope_region(deref_expr.id); for i in range(0u, derefs) { debug!("constrain_autoderefs(deref_expr=?, derefd_ty={}, derefs={:?}/{:?}", rcx.fcx.infcx().ty_to_string(derefd_ty), @@ -1154,7 +1258,7 @@ fn constrain_autoderefs(rcx: &mut Rcx, let fn_sig = ty::ty_fn_sig(method.ty); let self_ty = *fn_sig.inputs.get(0); let (m, r) = match ty::get(self_ty).sty { - ty::ty_rptr(r, ref m) => (m.mutbl, r), + ty::ty_rptr(ref r, ref m) => (m.mutbl, r), _ => rcx.tcx().sess.span_bug(deref_expr.span, format!("bad overloaded deref type {}", method.ty.repr(rcx.tcx())).as_slice()) @@ -1162,24 +1266,33 @@ fn constrain_autoderefs(rcx: &mut Rcx, { let mc = mc::MemCategorizationContext::new(rcx); let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i)); - link_region(rcx, deref_expr.span, r, - ty::BorrowKind::from_mutbl(m), self_cmt); + link_region(rcx, + deref_expr.span, + r, + ty::BorrowKind::from_mutbl(m), + self_cmt); } // Specialized version of constrain_call. - type_must_outlive(rcx, infer::CallRcvr(deref_expr.span), - self_ty, r_deref_expr); - type_must_outlive(rcx, infer::CallReturn(deref_expr.span), - fn_sig.output, r_deref_expr); + type_must_outlive(rcx, + infer::CallRcvr(deref_expr.span), + self_ty, + &r_deref_expr); + type_must_outlive(rcx, + infer::CallReturn(deref_expr.span), + fn_sig.output, + &r_deref_expr); fn_sig.output } None => derefd_ty }; match ty::get(derefd_ty).sty { - ty::ty_rptr(r_ptr, _) => { - mk_subregion_due_to_dereference(rcx, deref_expr.span, - r_deref_expr, r_ptr); + ty::ty_rptr(ref r_ptr, _) => { + mk_subregion_due_to_dereference(rcx, + deref_expr.span, + &r_deref_expr, + r_ptr); } _ => {} } @@ -1195,17 +1308,15 @@ fn constrain_autoderefs(rcx: &mut Rcx, pub fn mk_subregion_due_to_dereference(rcx: &mut Rcx, deref_span: Span, - minimum_lifetime: ty::Region, - maximum_lifetime: ty::Region) { + minimum_lifetime: &ty::Region, + maximum_lifetime: &ty::Region) { rcx.fcx.mk_subr(infer::DerefPointer(deref_span), - minimum_lifetime, maximum_lifetime) + minimum_lifetime, + maximum_lifetime) } -fn constrain_index(rcx: &mut Rcx, - index_expr: &ast::Expr, - indexed_ty: ty::t) -{ +fn constrain_index(rcx: &mut Rcx, index_expr: &ast::Expr, indexed_ty: ty::t) { /*! * Invoked on any index expression that occurs. Checks that if * this is a slice being indexed, the lifetime of the pointer @@ -1215,26 +1326,27 @@ fn constrain_index(rcx: &mut Rcx, debug!("constrain_index(index_expr=?, indexed_ty={}", rcx.fcx.infcx().ty_to_string(indexed_ty)); - let r_index_expr = ty::ReScope(index_expr.id); + let r_index_expr = rcx.scope_region(index_expr.id); match ty::get(indexed_ty).sty { - ty::ty_rptr(r_ptr, mt) => match ty::get(mt.ty).sty { - ty::ty_vec(_, None) | ty::ty_str => { - rcx.fcx.mk_subr(infer::IndexSlice(index_expr.span), - r_index_expr, r_ptr); + ty::ty_rptr(ref r_ptr, mt) => { + match ty::get(mt.ty).sty { + ty::ty_vec(_, None) | ty::ty_str => { + rcx.fcx.mk_subr(infer::IndexSlice(index_expr.span), + &r_index_expr, + r_ptr); + } + _ => {} } - _ => {} - }, + } _ => {} } } -fn type_of_node_must_outlive( - rcx: &mut Rcx, - origin: infer::SubregionOrigin, - id: ast::NodeId, - minimum_lifetime: ty::Region) -{ +fn type_of_node_must_outlive(rcx: &mut Rcx, + origin: infer::SubregionOrigin, + id: ast::NodeId, + minimum_lifetime: &ty::Region) { /*! * Guarantees that any lifetimes which appear in the type of * the node `id` (after applying adjustments) are valid for at @@ -1251,9 +1363,11 @@ fn type_of_node_must_outlive( rcx.fcx.inh.adjustments.borrow().find(&id), |method_call| rcx.resolve_method_type(method_call)); debug!("constrain_regions_in_type_of_node(\ - ty={}, ty0={}, id={}, minimum_lifetime={:?})", - ty_to_string(tcx, ty), ty_to_string(tcx, ty0), - id, minimum_lifetime); + ty={}, ty0={}, id={}, minimum_lifetime={})", + ty_to_string(tcx, ty), + ty_to_string(tcx, ty0), + id, + minimum_lifetime); type_must_outlive(rcx, origin, ty, minimum_lifetime); } @@ -1291,7 +1405,7 @@ fn link_local(rcx: &Rcx, local: &ast::Local) { link_pattern(rcx, mc, discr_cmt, &*local.pat); } -fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) { +fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[Gc]) { /*! * Computes the guarantors for any ref bindings in a match and * then ensures that the lifetime of the resulting pointer is @@ -1331,7 +1445,9 @@ fn link_pattern(rcx: &Rcx, ast::PatVec(_, Some(ref slice_pat), _) => { match mc.cat_slice_pattern(sub_cmt, &**slice_pat) { Ok((slice_cmt, slice_mutbl, slice_r)) => { - link_region(rcx, sub_pat.span, slice_r, + link_region(rcx, + sub_pat.span, + &slice_r, ty::BorrowKind::from_mutbl(slice_mutbl), slice_cmt); } @@ -1358,8 +1474,10 @@ fn link_autoref(rcx: &Rcx, debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx())); match *autoref { - ty::AutoPtr(r, m, _) => { - link_region(rcx, expr.span, r, + ty::AutoPtr(ref r, m, _) => { + link_region(rcx, + expr.span, + r, ty::BorrowKind::from_mutbl(m), expr_cmt); } @@ -1367,9 +1485,7 @@ fn link_autoref(rcx: &Rcx, } } -fn link_by_ref(rcx: &Rcx, - expr: &ast::Expr, - callee_scope: ast::NodeId) { +fn link_by_ref(rcx: &Rcx, expr: &ast::Expr, callee_scope: ast::NodeId) { /*! * Computes the guarantor for cases where the `expr` is * being passed by implicit reference and must outlive @@ -1381,8 +1497,20 @@ fn link_by_ref(rcx: &Rcx, expr.repr(tcx), callee_scope); let mc = mc::MemCategorizationContext::new(rcx); let expr_cmt = ignore_err!(mc.cat_expr(expr)); - let borrow_region = ty::ReScope(callee_scope); - link_region(rcx, expr.span, borrow_region, ty::ImmBorrow, expr_cmt); + match rcx.loop_analysis { + None => {} + Some(ref loop_analysis) => { + let borrow_region = ty::ReSemeRegion(SemeRegion::from_scope( + rcx.fcx.tcx(), + loop_analysis, + callee_scope)); + link_region(rcx, + expr.span, + &borrow_region, + ty::ImmBorrow, + expr_cmt); + } + } } fn link_region_from_node_type(rcx: &Rcx, @@ -1401,14 +1529,17 @@ fn link_region_from_node_type(rcx: &Rcx, let tcx = rcx.fcx.ccx.tcx; debug!("rptr_ty={}", ty_to_string(tcx, rptr_ty)); let r = ty::ty_region(tcx, span, rptr_ty); - link_region(rcx, span, r, ty::BorrowKind::from_mutbl(mutbl), + link_region(rcx, + span, + &r, + ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed); } } fn link_region(rcx: &Rcx, span: Span, - borrow_region: ty::Region, + borrow_region: &ty::Region, borrow_kind: ty::BorrowKind, borrow_cmt: mc::cmt) { /*! @@ -1428,10 +1559,10 @@ fn link_region(rcx: &Rcx, borrow_kind.repr(rcx.tcx()), borrow_cmt.repr(rcx.tcx())); match borrow_cmt.cat.clone() { - mc::cat_deref(ref_cmt, _, - mc::Implicit(ref_kind, ref_region)) | - mc::cat_deref(ref_cmt, _, - mc::BorrowedPtr(ref_kind, ref_region)) => { + mc::cat_deref(ref ref_cmt, _, + mc::Implicit(ref_kind, ref ref_region)) | + mc::cat_deref(ref ref_cmt, _, + mc::BorrowedPtr(ref_kind, ref ref_region)) => { match link_reborrowed_region(rcx, span, borrow_region, borrow_kind, ref_cmt, ref_region, ref_kind) { @@ -1473,13 +1604,12 @@ fn link_region(rcx: &Rcx, fn link_reborrowed_region(rcx: &Rcx, span: Span, - borrow_region: ty::Region, + borrow_region: &ty::Region, borrow_kind: ty::BorrowKind, - ref_cmt: mc::cmt, - ref_region: ty::Region, + ref_cmt: &mc::cmt, + ref_region: &ty::Region, ref_kind: ty::BorrowKind) - -> Option<(mc::cmt, ty::BorrowKind)> -{ + -> Option<(mc::cmt, ty::BorrowKind)> { /*! * This is the most complicated case: the path being borrowed is * itself the referent of a borrowed pointer. Let me give an @@ -1614,7 +1744,7 @@ fn link_reborrowed_region(rcx: &Rcx, ty::MutBorrow | ty::UniqueImmBorrow => ty::UniqueImmBorrow }; - return Some((ref_cmt, new_borrow_kind)); + return Some(((*ref_cmt).clone(), new_borrow_kind)); } } } @@ -1811,8 +1941,7 @@ fn adjust_upvar_borrow_kind(upvar_id: ty::UpvarId, fn type_must_outlive(rcx: &mut Rcx, origin: infer::SubregionOrigin, ty: ty::t, - region: ty::Region) -{ + region: &ty::Region) { /*! * Ensures that all borrowed data reachable via `ty` outlives `region`. */ @@ -1829,17 +1958,23 @@ fn type_must_outlive(rcx: &mut Rcx, for constraint in constraints.iter() { debug!("constraint: {}", constraint.repr(rcx.tcx())); match *constraint { - regionmanip::RegionSubRegionConstraint(None, r_a, r_b) => { + regionmanip::RegionSubRegionConstraint(None, + ref r_a, + ref r_b) => { rcx.fcx.mk_subr(origin.clone(), r_a, r_b); } - regionmanip::RegionSubRegionConstraint(Some(ty), r_a, r_b) => { + regionmanip::RegionSubRegionConstraint(Some(ty), + ref r_a, + ref r_b) => { let o1 = infer::ReferenceOutlivesReferent(ty, origin.span()); rcx.fcx.mk_subr(o1, r_a, r_b); } - regionmanip::RegionSubParamConstraint(None, r_a, param_b) => { + regionmanip::RegionSubParamConstraint(None, ref r_a, param_b) => { param_must_outlive(rcx, origin.clone(), r_a, param_b); } - regionmanip::RegionSubParamConstraint(Some(ty), r_a, param_b) => { + regionmanip::RegionSubParamConstraint(Some(ty), + ref r_a, + param_b) => { let o1 = infer::ReferenceOutlivesReferent(ty, origin.span()); param_must_outlive(rcx, o1, r_a, param_b); } @@ -1849,7 +1984,7 @@ fn type_must_outlive(rcx: &mut Rcx, fn param_must_outlive(rcx: &Rcx, origin: infer::SubregionOrigin, - region: ty::Region, + region: &ty::Region, param_ty: ty::ParamTy) { let param_env = &rcx.fcx.inh.param_env; @@ -1871,7 +2006,14 @@ fn param_must_outlive(rcx: &Rcx, // Collect default bound of fn body that applies to all in scope // type parameters: - param_bounds.push(param_env.implicit_region_bound); + match param_env.implicit_region_bound { + ty::ScopeImplicitRegionBound(scope_id) => { + param_bounds.push(rcx.scope_region(scope_id)) + } + ty::RegionImplicitRegionBound(ref region) => { + param_bounds.push((*region).clone()) + } + } // Finally, collect regions we scraped from the well-formedness // constraints in the fn signature. To do that, we walk the list @@ -1891,7 +2033,7 @@ fn param_must_outlive(rcx: &Rcx, p.repr(rcx.tcx()), p.def_id); if param_ty == *p { - param_bounds.push(*r); + param_bounds.push((*r).clone()); } } @@ -1903,3 +2045,5 @@ fn param_must_outlive(rcx: &Rcx, region, param_bounds); } + + diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index 577da159162fc..bc5bdd0dcbe2d 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -33,11 +33,11 @@ pub fn replace_late_bound_regions_in_fn_sig( let fn_sig = { let mut f = ty_fold::RegionFolder::regions(tcx, |r| { debug!("region r={}", r.to_string()); - match r { + match *r { ty::ReLateBound(s, br) if s == fn_sig.binder_id => { - *map.find_or_insert_with(br, |_| mapf(br)) + (*map.find_or_insert_with(br, |_| mapf(br))).clone() } - _ => r + _ => (*r).clone() } }); ty_fold::super_fold_sig(&mut f, fn_sig) @@ -57,12 +57,10 @@ struct Wf<'a> { out: Vec, } -pub fn region_wf_constraints( - tcx: &ty::ctxt, - ty: ty::t, - outer_region: ty::Region) - -> Vec -{ +pub fn region_wf_constraints(tcx: &ty::ctxt, + ty: ty::t, + outer_region: &ty::Region) + -> Vec { /*! * This routine computes the well-formedness constraints that must * hold for the type `ty` to appear in a context with lifetime @@ -70,7 +68,7 @@ pub fn region_wf_constraints( */ let mut stack = Vec::new(); - stack.push((outer_region, None)); + stack.push(((*outer_region).clone(), None)); let mut wf = Wf { tcx: tcx, stack: stack, out: Vec::new() }; @@ -101,7 +99,7 @@ impl<'a> Wf<'a> { self.accumulate_from_closure_ty(ty, c); } - ty::ty_unboxed_closure(_, region) => { + ty::ty_unboxed_closure(_, ref region) => { // An "unboxed closure type" is basically // modeled here as equivalent to a struct like // @@ -130,7 +128,7 @@ impl<'a> Wf<'a> { self.accumulate_from_ty(t) } - ty::ty_rptr(r_b, mt) => { + ty::ty_rptr(ref r_b, mt) => { self.accumulate_from_rptr(ty, r_b, mt.ty); } @@ -162,7 +160,7 @@ impl<'a> Wf<'a> { fn accumulate_from_rptr(&mut self, ty: ty::t, - r_b: ty::Region, + r_b: &ty::Region, ty_b: ty::t) { // We are walking down a type like this, and current // position is indicated by caret: @@ -178,13 +176,12 @@ impl<'a> Wf<'a> { // Now we push `'b` onto the stack, because it must // constrain any borrowed content we find within `T`. - self.stack.push((r_b, Some(ty))); + self.stack.push(((*r_b).clone(), Some(ty))); self.accumulate_from_ty(ty_b); self.stack.pop().unwrap(); } - fn push_region_constraint_from_top(&mut self, - r_b: ty::Region) { + fn push_region_constraint_from_top(&mut self, r_b: &ty::Region) { /*! * Pushes a constraint that `r_b` must outlive the * top region on the stack. @@ -203,42 +200,44 @@ impl<'a> Wf<'a> { // be on top of stack and `'b` will be the lifetime of the content // we just found. So we add constraint that `'a <= 'b`. - let &(r_a, opt_ty) = self.stack.last().unwrap(); - self.push_sub_region_constraint(opt_ty, r_a, r_b); + let (r_a, opt_ty) = (*self.stack.last().unwrap()).clone(); + self.push_sub_region_constraint(opt_ty, &r_a, r_b); } fn push_sub_region_constraint(&mut self, opt_ty: Option, - r_a: ty::Region, - r_b: ty::Region) { + r_a: &ty::Region, + r_b: &ty::Region) { /*! Pushes a constraint that `r_a <= r_b`, due to `opt_ty` */ - self.out.push(RegionSubRegionConstraint(opt_ty, r_a, r_b)); + self.out.push(RegionSubRegionConstraint(opt_ty, + (*r_a).clone(), + (*r_b).clone())); } - fn push_param_constraint_from_top(&mut self, - param_ty: ty::ParamTy) { + fn push_param_constraint_from_top(&mut self, param_ty: ty::ParamTy) { /*! * Pushes a constraint that `param_ty` must outlive the * top region on the stack. */ - let &(region, opt_ty) = self.stack.last().unwrap(); - self.push_param_constraint(region, opt_ty, param_ty); + let (region, opt_ty) = (*self.stack.last().unwrap()).clone(); + self.push_param_constraint(®ion, opt_ty, param_ty); } fn push_param_constraint(&mut self, - region: ty::Region, + region: &ty::Region, opt_ty: Option, param_ty: ty::ParamTy) { /*! Pushes a constraint that `region <= param_ty`, due to `opt_ty` */ - self.out.push(RegionSubParamConstraint(opt_ty, region, param_ty)); + self.out.push(RegionSubParamConstraint(opt_ty, + (*region).clone(), + param_ty)); } fn accumulate_from_adt(&mut self, ty: ty::t, def_id: ast::DefId, - substs: &Substs) - { + substs: &Substs) { // The generic declarations from the type, appropriately // substituted for the actual substitutions. let generics = @@ -254,7 +253,7 @@ impl<'a> Wf<'a> { let region_variances = variances.regions.get_slice(space); let region_param_defs = generics.regions.get_slice(space); assert_eq!(region_params.len(), region_variances.len()); - for (®ion_param, (®ion_variance, region_param_def)) in + for (region_param, (®ion_variance, region_param_def)) in region_params.iter().zip( region_variances.iter().zip( region_param_defs.iter())) @@ -285,7 +284,7 @@ impl<'a> Wf<'a> { } } - for ®ion_bound in region_param_def.bounds.iter() { + for region_bound in region_param_def.bounds.iter() { // The type declared a constraint like // // 'b : 'a @@ -327,8 +326,8 @@ impl<'a> Wf<'a> { // Inspect bounds on this type parameter for any // region bounds. - for &r in type_param_def.bounds.opt_region_bound.iter() { - self.stack.push((r, Some(ty))); + for r in type_param_def.bounds.opt_region_bound.iter() { + self.stack.push(((*r).clone(), Some(ty))); self.accumulate_from_ty(type_param_ty); self.stack.pop().unwrap(); } @@ -336,12 +335,9 @@ impl<'a> Wf<'a> { } } - fn accumulate_from_closure_ty(&mut self, - ty: ty::t, - c: &ty::ClosureTy) - { + fn accumulate_from_closure_ty(&mut self, ty: ty::t, c: &ty::ClosureTy) { match c.store { - ty::RegionTraitStore(r_b, _) => { + ty::RegionTraitStore(ref r_b, _) => { self.push_region_constraint_from_top(r_b); } ty::UniqTraitStore => { } @@ -388,7 +384,7 @@ impl<'a> Wf<'a> { // The content of this object type must outlive // `bounds.region_bound`: - let r_c = bounds.region_bound; + let r_c = &bounds.region_bound; self.push_region_constraint_from_top(r_c); // And then, in turn, to be well-formed, the @@ -399,10 +395,12 @@ impl<'a> Wf<'a> { [], bounds.builtin_bounds, []); - for &r_d in required_region_bounds.iter() { + for r_d in required_region_bounds.iter() { // Each of these is an instance of the `'c <= 'b` // constraint above - self.out.push(RegionSubRegionConstraint(Some(ty), r_d, r_c)); + self.out.push(RegionSubRegionConstraint(Some(ty), + (*r_d).clone(), + (*r_c).clone())); } } } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index da4bc4dbc7694..4063d9e0efe0e 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -648,7 +648,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { (&ty::ty_uniq(..), &ty::ty_uniq(..) ) | (&ty::ty_ptr(..), &ty::ty_ptr(..) ) | (&ty::ty_ptr(..), &ty::ty_rptr(..)) => {} - (&ty::ty_rptr(r_t, _), &ty::ty_rptr(r_s, _)) => { + (&ty::ty_rptr(ref r_t, _), &ty::ty_rptr(ref r_s, _)) => { infer::mk_subr(fcx.infcx(), infer::RelateObjectBound(ex.span), r_t, @@ -876,8 +876,12 @@ fn trait_cast_types(fcx: &FnCtxt, sp: Span) -> Option<(ty::t, ty::t)> { match k { - &ty::UnsizeVtable(bounds, def_id, ref substs) => { - Some((src_ty, ty::mk_trait(fcx.tcx(), def_id, substs.clone(), bounds))) + &ty::UnsizeVtable(ref bounds, def_id, ref substs) => { + Some((src_ty, + ty::mk_trait(fcx.tcx(), + def_id, + substs.clone(), + (*bounds).clone()))) } &ty::UnsizeStruct(box ref k, tp_index) => match ty::get(src_ty).sty { ty::ty_struct(_, ref substs) => { @@ -989,12 +993,12 @@ pub fn resolve_impl(tcx: &ty::ctxt, let trait_def = ty::lookup_trait_def(tcx, impl_trait_ref.def_id); let vtbls = lookup_vtables(&vcx, - impl_item.span, - &trait_def.generics.types, - &impl_trait_ref.substs, - false); + impl_item.span, + &trait_def.generics.types, + &impl_trait_ref.substs, + false); - infcx.resolve_regions_and_report_errors(); + infcx.resolve_regions_and_report_errors(None); let vtbls = writeback::resolve_impl_res(infcx, impl_item.span, &vtbls); let impl_def_id = ast_util::local_def(impl_item.id); @@ -1014,7 +1018,10 @@ pub fn trans_resolve_method(tcx: &ty::ctxt, id: ast::NodeId, let unboxed_closures = RefCell::new(DefIdMap::new()); let vcx = VtableContext { infcx: &infer::new_infer_ctxt(tcx), - param_env: &ty::construct_parameter_environment(tcx, &ty::Generics::empty(), id), + param_env: &ty::construct_parameter_environment( + tcx, + &ty::Generics::empty(), + id), unboxed_closures: &unboxed_closures, }; diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 7951c8dfc1980..49767e717b88f 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -199,8 +199,8 @@ impl<'cx> WritebackCx<'cx> { } for (upvar_id, upvar_borrow) in self.fcx.inh.upvar_borrow_map.borrow().iter() { - let r = upvar_borrow.region; - let r = self.resolve(&r, ResolvingUpvar(*upvar_id)); + let r = self.resolve(&upvar_borrow.region, + ResolvingUpvar(*upvar_id)); let new_upvar_borrow = ty::UpvarBorrow { kind: upvar_borrow.kind, region: r }; debug!("Upvar borrow for {} resolved to {}", @@ -494,7 +494,7 @@ impl<'cx> TypeFolder for Resolver<'cx> { } } - fn fold_region(&mut self, r: ty::Region) -> ty::Region { + fn fold_region(&mut self, r: &ty::Region) -> ty::Region { match resolve_region(self.infcx, r, resolve_all | force_all) { Ok(r) => r, Err(e) => { diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 9c58a4c79f057..3cf6d46f07780 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -810,7 +810,7 @@ fn subst_receiver_types_in_method_ty(tcx: &ty::ctxt, method.ident, method_generics, method_fty, - method.explicit_self, + method.explicit_self.clone(), method.vis, new_def_id, ImplContainer(impl_id), diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index c22baa1d9e5d3..57528e6bf4550 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -1416,7 +1416,7 @@ fn check_method_self_type( format!("mismatched self type: expected `{}`", ppaux::ty_to_string(crate_context.tcx, required_type)) })); - infcx.resolve_regions_and_report_errors(); + infcx.resolve_regions_and_report_errors(None); } _ => {} } diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index 7763a992c8f94..88f1cff4e91c3 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -216,7 +216,7 @@ impl<'f> Coerce<'f> { pub fn subtype(&self, a: ty::t, b: ty::t) -> CoerceResult { match Sub(self.get_ref().clone()).tys(a, b) { Ok(_) => Ok(None), // No coercion required. - Err(ref e) => Err(*e) + Err(ref e) => Err((*e).clone()) } } @@ -266,7 +266,7 @@ impl<'f> Coerce<'f> { }; let a_borrowed = ty::mk_rptr(self.get_ref().infcx.tcx, - r_borrow, + r_borrow.clone(), mt {ty: inner_ty, mutbl: mutbl_b}); try!(sub.tys(a_borrowed, b)); @@ -292,7 +292,8 @@ impl<'f> Coerce<'f> { let sub = Sub(self.get_ref().clone()); let coercion = Coercion(self.get_ref().trace.clone()); let r_borrow = self.get_ref().infcx.next_region_var(coercion); - let unsized_ty = ty::mk_slice(self.get_ref().infcx.tcx, r_borrow, + let unsized_ty = ty::mk_slice(self.get_ref().infcx.tcx, + r_borrow.clone(), mt {ty: t_a, mutbl: mutbl_b}); try!(self.get_ref().infcx.try(|| sub.tys(unsized_ty, b))); Ok(Some(AutoDerefRef(AutoDerefRef { @@ -334,7 +335,7 @@ impl<'f> Coerce<'f> { let coercion = Coercion(self.get_ref().trace.clone()); let r_borrow = self.get_ref().infcx.next_region_var(coercion); let ty = ty::mk_rptr(self.get_ref().infcx.tcx, - r_borrow, + r_borrow.clone(), ty::mt{ty: ty, mutbl: mt_b.mutbl}); try!(self.get_ref().infcx.try(|| sub.tys(ty, b))); debug!("Success, coerced with AutoDerefRef(1, \ @@ -407,12 +408,16 @@ impl<'f> Coerce<'f> { Some((ty, ty::UnsizeLength(len))) } (&ty::ty_trait(..), &ty::ty_trait(..)) => None, - (_, &ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds })) => { + (_, &ty::ty_trait(box ty::TyTrait { + def_id, + ref substs, + ref bounds + })) => { let ty = ty::mk_trait(tcx, def_id, substs.clone(), - bounds); - Some((ty, ty::UnsizeVtable(bounds, + (*bounds).clone()); + Some((ty, ty::UnsizeVtable((*bounds).clone(), def_id, substs.clone()))) } @@ -479,8 +484,15 @@ impl<'f> Coerce<'f> { let r_a = self.get_ref().infcx.next_region_var(coercion); self.coerce_object(a, sty_a, b, - |tr| ty::mk_rptr(tcx, r_a, ty::mt{ mutbl: b_mutbl, ty: tr }), - || AutoPtr(r_a, b_mutbl, None)) + |tr| { + ty::mk_rptr(tcx, + r_a.clone(), + ty::mt { + mutbl: b_mutbl, + ty: tr, + }) + }, + || AutoPtr(r_a.clone(), b_mutbl, None)) } fn coerce_unsafe_object(&self, @@ -514,10 +526,13 @@ impl<'f> Coerce<'f> { ty::ty_trait(box ty::TyTrait { def_id, ref substs, - bounds, + ref bounds, .. }) => { - let tr = ty::mk_trait(tcx, def_id, substs.clone(), bounds); + let tr = ty::mk_trait(tcx, + def_id, + substs.clone(), + (*bounds).clone()); try!(self.subtype(mk_ty(tr), b)); Ok(Some(AutoDerefRef(AutoDerefRef { autoderefs: 1, @@ -575,7 +590,7 @@ impl<'f> Coerce<'f> { _ => return self.subtype(a, b) }; - let adj = ty::AutoAddEnv(fn_ty_b.store); + let adj = ty::AutoAddEnv(fn_ty_b.store.clone()); let a_closure = ty::mk_closure(self.get_ref().infcx.tcx, ty::ClosureTy { sig: fn_ty_a.sig.clone(), diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index 2a44ef9de2b1b..8e48e021f94aa 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -162,14 +162,14 @@ pub trait Combine { assert_eq!(num_region_params, b_rs.len()); let mut rs = vec!(); for i in range(0, num_region_params) { - let a_r = a_rs[i]; - let b_r = b_rs[i]; + let a_r = &a_rs[i]; + let b_r = &b_rs[i]; let variance = variances[i]; let r = match variance { ty::Invariant => this.equate().regions(a_r, b_r), ty::Covariant => this.regions(a_r, b_r), ty::Contravariant => this.contraregions(a_r, b_r), - ty::Bivariant => Ok(a_r), + ty::Bivariant => Ok((*a_r).clone()), }; rs.push(try!(r)); } @@ -190,24 +190,25 @@ pub trait Combine { fn closure_tys(&self, a: &ty::ClosureTy, b: &ty::ClosureTy) -> cres { - let store = match (a.store, b.store) { - (ty::RegionTraitStore(a_r, a_m), - ty::RegionTraitStore(b_r, b_m)) if a_m == b_m => { + let store = match (&a.store, &b.store) { + (&ty::RegionTraitStore(ref a_r, a_m), + &ty::RegionTraitStore(ref b_r, b_m)) if a_m == b_m => { let r = try!(self.contraregions(a_r, b_r)); ty::RegionTraitStore(r, a_m) } - _ if a.store == b.store => { - a.store - } + _ if a.store == b.store => a.store.clone(), _ => { - return Err(ty::terr_sigil_mismatch(expected_found(self, a.store, b.store))) + return Err(ty::terr_sigil_mismatch(expected_found( + self, + a.store.clone(), + b.store.clone()))) } }; let fn_style = try!(self.fn_styles(a.fn_style, b.fn_style)); let onceness = try!(self.oncenesses(a.onceness, b.onceness)); - let bounds = try!(self.existential_bounds(a.bounds, b.bounds)); + let bounds = try!(self.existential_bounds(&a.bounds, &b.bounds)); let sig = try!(self.fn_sigs(&a.sig, &b.sig)); let abi = try!(self.abi(a.abi, b.abi)); Ok(ty::ClosureTy { @@ -239,11 +240,10 @@ pub trait Combine { fn oncenesses(&self, a: Onceness, b: Onceness) -> cres; fn existential_bounds(&self, - a: ty::ExistentialBounds, - b: ty::ExistentialBounds) - -> cres - { - let r = try!(self.contraregions(a.region_bound, b.region_bound)); + a: &ty::ExistentialBounds, + b: &ty::ExistentialBounds) + -> cres { + let r = try!(self.contraregions(&a.region_bound, &b.region_bound)); let nb = try!(self.builtin_bounds(a.builtin_bounds, b.builtin_bounds)); Ok(ty::ExistentialBounds { region_bound: r, builtin_bounds: nb }) @@ -254,32 +254,35 @@ pub trait Combine { b: ty::BuiltinBounds) -> cres; - fn contraregions(&self, a: ty::Region, b: ty::Region) + fn contraregions(&self, a: &ty::Region, b: &ty::Region) -> cres; - fn regions(&self, a: ty::Region, b: ty::Region) -> cres; + fn regions(&self, a: &ty::Region, b: &ty::Region) -> cres; fn trait_stores(&self, vk: ty::terr_vstore_kind, - a: ty::TraitStore, - b: ty::TraitStore) + a: &ty::TraitStore, + b: &ty::TraitStore) -> cres { debug!("{}.trait_stores(a={}, b={})", self.tag(), a, b); match (a, b) { - (ty::RegionTraitStore(a_r, a_m), - ty::RegionTraitStore(b_r, b_m)) if a_m == b_m => { + (&ty::RegionTraitStore(ref a_r, a_m), + &ty::RegionTraitStore(ref b_r, b_m)) if a_m == b_m => { self.contraregions(a_r, b_r).and_then(|r| { Ok(ty::RegionTraitStore(r, a_m)) }) } _ if a == b => { - Ok(a) + Ok((*a).clone()) } _ => { - Err(ty::terr_trait_stores_differ(vk, expected_found(self, a, b))) + Err(ty::terr_trait_stores_differ(vk, expected_found( + self, + (*a).clone(), + (*b).clone()))) } } @@ -454,7 +457,7 @@ pub fn super_tys(this: &C, a: ty::t, b: ty::t) -> cres { if a_.def_id == b_.def_id => { debug!("Trying to match traits {:?} and {:?}", a, b); let substs = try!(this.substs(a_.def_id, &a_.substs, &b_.substs)); - let bounds = try!(this.existential_bounds(a_.bounds, b_.bounds)); + let bounds = try!(this.existential_bounds(&a_.bounds, &b_.bounds)); Ok(ty::mk_trait(tcx, a_.def_id, substs.clone(), @@ -467,8 +470,8 @@ pub fn super_tys(this: &C, a: ty::t, b: ty::t) -> cres { Ok(ty::mk_struct(tcx, a_id, substs)) } - (&ty::ty_unboxed_closure(a_id, a_region), - &ty::ty_unboxed_closure(b_id, b_region)) + (&ty::ty_unboxed_closure(a_id, ref a_region), + &ty::ty_unboxed_closure(b_id, ref b_region)) if a_id == b_id => { // All ty_unboxed_closure types with the same id represent // the (anonymous) type of the same closure expression. So @@ -491,7 +494,7 @@ pub fn super_tys(this: &C, a: ty::t, b: ty::t) -> cres { check_ptr_to_unsized(this, a, b, a_mt.ty, b_mt.ty, ty::mk_ptr(tcx, mt)) } - (&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => { + (&ty::ty_rptr(ref a_r, ref a_mt), &ty::ty_rptr(ref b_r, ref b_mt)) => { let r = try!(this.contraregions(a_r, b_r)); // FIXME(14985) If we have mutable references to trait objects, we // used to use covariant subtyping. I have preserved this behaviour, diff --git a/src/librustc/middle/typeck/infer/equate.rs b/src/librustc/middle/typeck/infer/equate.rs index 223d37ee1ea62..42491d0e12089 100644 --- a/src/librustc/middle/typeck/infer/equate.rs +++ b/src/librustc/middle/typeck/infer/equate.rs @@ -47,17 +47,18 @@ impl<'f> Combine for Equate<'f> { self.tys(a, b) } - fn contraregions(&self, a: ty::Region, b: ty::Region) -> cres { + fn contraregions(&self, a: &ty::Region, b: &ty::Region) + -> cres { self.regions(a, b) } - fn regions(&self, a: ty::Region, b: ty::Region) -> cres { + fn regions(&self, a: &ty::Region, b: &ty::Region) -> cres { debug!("{}.regions({}, {})", self.tag(), a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx)); self.infcx().region_vars.make_eqregion(Subtype(self.trace()), a, b); - Ok(a) + Ok((*a).clone()) } fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres { diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index bd355d2f580b9..d4aa705d8d21b 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -98,8 +98,7 @@ use util::ppaux::note_and_explain_region; use util::ppaux::UserString; pub trait ErrorReporting { - fn report_region_errors(&self, - errors: &Vec); + fn report_region_errors(&self, errors: &Vec); fn process_errors(&self, errors: &Vec) -> Vec; @@ -119,28 +118,28 @@ pub trait ErrorReporting { fn report_concrete_failure(&self, origin: SubregionOrigin, - sub: Region, - sup: Region); + sub: &Region, + sup: &Region); fn report_param_bound_failure(&self, - origin: SubregionOrigin, + origin: &SubregionOrigin, param_ty: ty::ParamTy, - sub: Region, - sups: Vec); + sub: &Region, + sups: &[Region]); fn report_sub_sup_conflict(&self, - var_origin: RegionVariableOrigin, - sub_origin: SubregionOrigin, - sub_region: Region, - sup_origin: SubregionOrigin, - sup_region: Region); + var_origin: &RegionVariableOrigin, + sub_origin: &SubregionOrigin, + sub_region: &Region, + sup_origin: &SubregionOrigin, + sup_region: &Region); fn report_sup_sup_conflict(&self, - var_origin: RegionVariableOrigin, - origin1: SubregionOrigin, - region1: Region, - origin2: SubregionOrigin, - region2: Region); + var_origin: &RegionVariableOrigin, + origin1: &SubregionOrigin, + region1: &Region, + origin2: &SubregionOrigin, + region2: &Region); fn report_processed_errors(&self, var_origin: &[RegionVariableOrigin], @@ -151,11 +150,9 @@ pub trait ErrorReporting { } trait ErrorReportingHelpers { - fn report_inference_failure(&self, - var_origin: RegionVariableOrigin); + fn report_inference_failure(&self, var_origin: &RegionVariableOrigin); - fn note_region_origin(&self, - origin: &SubregionOrigin); + fn note_region_origin(&self, origin: &SubregionOrigin); fn give_expl_lifetime_param(&self, decl: &ast::FnDecl, @@ -167,31 +164,38 @@ trait ErrorReportingHelpers { } impl<'a> ErrorReporting for InferCtxt<'a> { - fn report_region_errors(&self, - errors: &Vec) { + fn report_region_errors(&self, errors: &Vec) { let p_errors = self.process_errors(errors); let errors = if p_errors.is_empty() { errors } else { &p_errors }; for error in errors.iter() { match error.clone() { - ConcreteFailure(origin, sub, sup) => { - self.report_concrete_failure(origin, sub, sup); + ConcreteFailure(ref origin, ref sub, ref sup) => { + self.report_concrete_failure((*origin).clone(), + sub, + sup); } - ParamBoundFailure(origin, param_ty, sub, sups) => { - self.report_param_bound_failure(origin, param_ty, sub, sups); + ParamBoundFailure(ref origin, + param_ty, + ref sub, + ref sups) => { + self.report_param_bound_failure(origin, + param_ty, + sub, + sups.as_slice()); } - SubSupConflict(var_origin, - sub_origin, sub_r, - sup_origin, sup_r) => { + SubSupConflict(ref var_origin, + ref sub_origin, ref sub_r, + ref sup_origin, ref sup_r) => { self.report_sub_sup_conflict(var_origin, sub_origin, sub_r, sup_origin, sup_r); } - SupSupConflict(var_origin, - origin1, r1, - origin2, r2) => { + SupSupConflict(ref var_origin, + ref origin1, ref r1, + ref origin2, ref r2) => { self.report_sup_sup_conflict(var_origin, origin1, r1, origin2, r2); @@ -231,7 +235,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> { infer::Subtype(trace) => Some(trace), _ => None, }; - match free_regions_from_same_fn(self.tcx, sub, sup) { + match free_regions_from_same_fn(self.tcx, &sub, &sup) { Some(ref same_frs) if trace.is_some() => { let trace = trace.unwrap(); let terr = ty::terr_regions_does_not_outlive(sup, @@ -244,7 +248,9 @@ impl<'a> ErrorReporting for InferCtxt<'a> { } SubSupConflict(var_origin, _, sub_r, _, sup_r) => { debug!("processing SubSupConflict") - match free_regions_from_same_fn(self.tcx, sub_r, sup_r) { + match free_regions_from_same_fn(self.tcx, + &sub_r, + &sup_r) { Some(ref same_frs) => { var_origins.push(var_origin); append_to_same_regions(&mut same_regions, same_frs); @@ -295,17 +301,17 @@ impl<'a> ErrorReporting for InferCtxt<'a> { } fn free_regions_from_same_fn(tcx: &ty::ctxt, - sub: Region, - sup: Region) + sub: &Region, + sup: &Region) -> Option { debug!("free_regions_from_same_fn(sub={:?}, sup={:?})", sub, sup); let (scope_id, fr1, fr2) = match (sub, sup) { - (ReFree(fr1), ReFree(fr2)) => { + (&ReFree(ref fr1), &ReFree(ref fr2)) => { if fr1.scope_id != fr2.scope_id { return None } assert!(fr1.scope_id == fr2.scope_id); - (fr1.scope_id, fr1, fr2) + (fr1.scope_id, (*fr1).clone(), (*fr2).clone()) }, _ => return None }; @@ -386,7 +392,6 @@ impl<'a> ErrorReporting for InferCtxt<'a> { trace: TypeTrace, terr: &ty::type_err) { self.report_type_error(trace, terr); - ty::note_and_explain_type_err(self.tcx, terr); } fn values_str(&self, values: &ValuePairs) -> Option { @@ -425,17 +430,17 @@ impl<'a> ErrorReporting for InferCtxt<'a> { } fn report_param_bound_failure(&self, - origin: SubregionOrigin, + origin: &SubregionOrigin, param_ty: ty::ParamTy, - sub: Region, - _sups: Vec) { + sub: &Region, + _sups: &[Region]) { // FIXME: it would be better to report the first error message // with the span of the parameter itself, rather than the span // where the error was detected. But that span is not readily // accessible. - match sub { + match *sub { ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { // Does the required lifetime have a nice name we can print? self.tcx.sess.span_err( @@ -477,16 +482,17 @@ impl<'a> ErrorReporting for InferCtxt<'a> { } } - self.note_region_origin(&origin); + self.note_region_origin(origin); } fn report_concrete_failure(&self, origin: SubregionOrigin, - sub: Region, - sup: Region) { + sub: &Region, + sup: &Region) { match origin { infer::Subtype(trace) => { - let terr = ty::terr_regions_does_not_outlive(sup, sub); + let terr = ty::terr_regions_does_not_outlive((*sup).clone(), + (*sub).clone()); self.report_and_explain_type_error(trace, &terr); } infer::Reborrow(span) => { @@ -785,11 +791,11 @@ impl<'a> ErrorReporting for InferCtxt<'a> { } fn report_sub_sup_conflict(&self, - var_origin: RegionVariableOrigin, - sub_origin: SubregionOrigin, - sub_region: Region, - sup_origin: SubregionOrigin, - sup_region: Region) { + var_origin: &RegionVariableOrigin, + sub_origin: &SubregionOrigin, + sub_region: &Region, + sup_origin: &SubregionOrigin, + sup_region: &Region) { self.report_inference_failure(var_origin); note_and_explain_region( @@ -798,7 +804,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> { sup_region, "..."); - self.note_region_origin(&sup_origin); + self.note_region_origin(sup_origin); note_and_explain_region( self.tcx, @@ -806,15 +812,15 @@ impl<'a> ErrorReporting for InferCtxt<'a> { sub_region, "..."); - self.note_region_origin(&sub_origin); + self.note_region_origin(sub_origin); } fn report_sup_sup_conflict(&self, - var_origin: RegionVariableOrigin, - origin1: SubregionOrigin, - region1: Region, - origin2: SubregionOrigin, - region2: Region) { + var_origin: &RegionVariableOrigin, + origin1: &SubregionOrigin, + region1: &Region, + origin2: &SubregionOrigin, + region2: &Region) { self.report_inference_failure(var_origin); note_and_explain_region( @@ -823,7 +829,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> { region1, "..."); - self.note_region_origin(&origin1); + self.note_region_origin(origin1); note_and_explain_region( self.tcx, @@ -831,7 +837,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> { region2, "..."); - self.note_region_origin(&origin2); + self.note_region_origin(origin2); } fn report_processed_errors(&self, @@ -839,11 +845,11 @@ impl<'a> ErrorReporting for InferCtxt<'a> { trace_origins: &[(TypeTrace, ty::type_err)], same_regions: &[SameRegions]) { for vo in var_origins.iter() { - self.report_inference_failure(vo.clone()); + self.report_inference_failure(vo); } self.give_suggestion(same_regions); - for &(ref trace, terr) in trace_origins.iter() { - self.report_type_error(trace.clone(), &terr); + for &(ref trace, ref terr) in trace_origins.iter() { + self.report_type_error(trace.clone(), terr); } } @@ -1418,9 +1424,8 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> { self.tcx.sess.span_note(span, msg.as_slice()); } - fn report_inference_failure(&self, - var_origin: RegionVariableOrigin) { - let var_description = match var_origin { + fn report_inference_failure(&self, var_origin: &RegionVariableOrigin) { + let var_description = match *var_origin { infer::MiscVariable(_) => "".to_string(), infer::PatternRegion(_) => " for pattern".to_string(), infer::AddrOfRegion(_) => " for borrow expression".to_string(), diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs index 8ae141ea19cc2..5f749d218e2bc 100644 --- a/src/librustc/middle/typeck/infer/glb.rs +++ b/src/librustc/middle/typeck/infer/glb.rs @@ -108,7 +108,7 @@ impl<'f> Combine for Glb<'f> { Ok(a.union(b)) } - fn regions(&self, a: ty::Region, b: ty::Region) -> cres { + fn regions(&self, a: &ty::Region, b: &ty::Region) -> cres { debug!("{}.regions({:?}, {:?})", self.tag(), a.repr(self.fields.infcx.tcx), @@ -117,7 +117,7 @@ impl<'f> Combine for Glb<'f> { Ok(self.fields.infcx.region_vars.glb_regions(Subtype(self.trace()), a, b)) } - fn contraregions(&self, a: ty::Region, b: ty::Region) + fn contraregions(&self, a: &ty::Region, b: &ty::Region) -> cres { self.lub().regions(a, b) } @@ -179,10 +179,11 @@ impl<'f> Combine for Glb<'f> { a_map: &HashMap, a_vars: &[RegionVid], b_vars: &[RegionVid], - r0: ty::Region) -> ty::Region { + r0: &ty::Region) + -> ty::Region { if !is_var_in_set(new_vars, r0) { assert!(!r0.is_bound()); - return r0; + return (*r0).clone(); } let tainted = this.fields.infcx.region_vars.tainted(mark, r0); @@ -191,19 +192,19 @@ impl<'f> Combine for Glb<'f> { let mut b_r = None; let mut only_new_vars = true; for r in tainted.iter() { - if is_var_in_set(a_vars, *r) { + if is_var_in_set(a_vars, r) { if a_r.is_some() { return fresh_bound_variable(this, new_binder_id); } else { - a_r = Some(*r); + a_r = Some((*r).clone()); } - } else if is_var_in_set(b_vars, *r) { + } else if is_var_in_set(b_vars, r) { if b_r.is_some() { return fresh_bound_variable(this, new_binder_id); } else { - b_r = Some(*r); + b_r = Some((*r).clone()); } - } else if !is_var_in_set(new_vars, *r) { + } else if !is_var_in_set(new_vars, r) { only_new_vars = false; } } @@ -235,7 +236,7 @@ impl<'f> Combine for Glb<'f> { } else if a_r.is_none() && b_r.is_none() { // Not related to bound variables from either fn: assert!(!r0.is_bound()); - return r0; + return (*r0).clone(); } else { // Other: return fresh_bound_variable(this, new_binder_id); diff --git a/src/librustc/middle/typeck/infer/lattice.rs b/src/librustc/middle/typeck/infer/lattice.rs index f09773d30b514..a9cbab5767800 100644 --- a/src/librustc/middle/typeck/infer/lattice.rs +++ b/src/librustc/middle/typeck/infer/lattice.rs @@ -120,7 +120,7 @@ pub fn var_ids(this: &T, -> Vec { map.iter().map(|(_, r)| match *r { ty::ReInfer(ty::ReVar(r)) => { r } - r => { + ref r => { this.infcx().tcx.sess.span_bug( this.trace().origin.span(), format!("found non-region-vid: {:?}", r).as_slice()); @@ -128,8 +128,8 @@ pub fn var_ids(this: &T, }).collect() } -pub fn is_var_in_set(new_vars: &[RegionVid], r: ty::Region) -> bool { - match r { +pub fn is_var_in_set(new_vars: &[RegionVid], r: &ty::Region) -> bool { + match *r { ty::ReInfer(ty::ReVar(ref v)) => new_vars.iter().any(|x| x == v), _ => false } diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs index 49760ac92bf7d..8b8c63a3fa0d4 100644 --- a/src/librustc/middle/typeck/infer/lub.rs +++ b/src/librustc/middle/typeck/infer/lub.rs @@ -102,12 +102,12 @@ impl<'f> Combine for Lub<'f> { Ok(a.intersection(b)) } - fn contraregions(&self, a: ty::Region, b: ty::Region) + fn contraregions(&self, a: &ty::Region, b: &ty::Region) -> cres { self.glb().regions(a, b) } - fn regions(&self, a: ty::Region, b: ty::Region) -> cres { + fn regions(&self, a: &ty::Region, b: &ty::Region) -> cres { debug!("{}.regions({}, {})", self.tag(), a.repr(self.fields.infcx.tcx), @@ -143,8 +143,14 @@ impl<'f> Combine for Lub<'f> { fold_regions_in_sig( self.fields.infcx.tcx, &sig0, - |r| generalize_region(self, mark, new_vars.as_slice(), - sig0.binder_id, &a_map, r)); + |r| { + generalize_region(self, + mark, + new_vars.as_slice(), + sig0.binder_id, + &a_map, + r) + }); return Ok(sig1); fn generalize_region(this: &Lub, @@ -152,13 +158,13 @@ impl<'f> Combine for Lub<'f> { new_vars: &[RegionVid], new_scope: NodeId, a_map: &HashMap, - r0: ty::Region) + r0: &ty::Region) -> ty::Region { // Regions that pre-dated the LUB computation stay as they are. if !is_var_in_set(new_vars, r0) { assert!(!r0.is_bound()); debug!("generalize_region(r0={:?}): not new variable", r0); - return r0; + return (*r0).clone(); } let tainted = this.fields.infcx.region_vars.tainted(mark, r0); @@ -166,12 +172,12 @@ impl<'f> Combine for Lub<'f> { // Variables created during LUB computation which are // *related* to regions that pre-date the LUB computation // stay as they are. - if !tainted.iter().all(|r| is_var_in_set(new_vars, *r)) { + if !tainted.iter().all(|r| is_var_in_set(new_vars, r)) { debug!("generalize_region(r0={:?}): \ non-new-variables found in {:?}", r0, tainted); assert!(!r0.is_bound()); - return r0; + return (*r0).clone(); } // Otherwise, the variable must be associated with at diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index f86857f97f654..15bbf828cf172 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -21,6 +21,7 @@ pub use middle::typeck::infer::resolve::{resolve_ivar, resolve_all}; pub use middle::typeck::infer::resolve::{resolve_nested_tvar}; pub use middle::typeck::infer::resolve::{resolve_rvar}; +use middle::loop_analysis::LoopAnalysis; use middle::subst; use middle::subst::Substs; use middle::ty::{TyVid, IntVid, FloatVid, RegionVid}; @@ -58,7 +59,6 @@ pub mod lub; pub mod region_inference; pub mod resolve; pub mod sub; -pub mod test; pub mod type_variable; pub mod unify; @@ -363,8 +363,8 @@ pub fn can_mk_subty(cx: &InferCtxt, a: ty::t, b: ty::t) -> ures { pub fn mk_subr(cx: &InferCtxt, origin: SubregionOrigin, - a: ty::Region, - b: ty::Region) { + a: &ty::Region, + b: &ty::Region) { debug!("mk_subr({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); let snapshot = cx.region_vars.start_snapshot(); cx.region_vars.make_subregion(origin, a, b); @@ -374,7 +374,7 @@ pub fn mk_subr(cx: &InferCtxt, pub fn verify_param_bound(cx: &InferCtxt, origin: SubregionOrigin, param_ty: ty::ParamTy, - a: ty::Region, + a: &ty::Region, bs: Vec) { debug!("verify_param_bound({}, {} <: {})", param_ty.repr(cx.tcx), @@ -460,7 +460,7 @@ pub fn resolve_type(cx: &InferCtxt, cx.commit_unconditionally(|| resolver.resolve_type_chk(a)) } -pub fn resolve_region(cx: &InferCtxt, r: ty::Region, modes: uint) +pub fn resolve_region(cx: &InferCtxt, r: &ty::Region, modes: uint) -> fres { let mut resolver = resolver(cx, modes, None); resolver.resolve_region_chk(r) @@ -474,7 +474,7 @@ trait then { impl then for ures { fn then(&self, f: || -> Result) -> Result { - self.and_then(|_i| f()) + self.clone().and_then(|_i| f()) } } @@ -486,7 +486,7 @@ impl ToUres for cres { fn to_ures(&self) -> ures { match *self { Ok(ref _v) => Ok(()), - Err(ref e) => Err((*e)) + Err(ref e) => Err((*e).clone()) } } } @@ -627,10 +627,7 @@ impl<'a> InferCtxt<'a> { r } - pub fn add_given(&self, - sub: ty::FreeRegion, - sup: ty::RegionVid) - { + pub fn add_given(&self, sub: ty::FreeRegion, sup: ty::RegionVid) { self.region_vars.add_given(sub, sup); } } @@ -701,9 +698,12 @@ impl<'a> InferCtxt<'a> { self.region_vars.new_bound(binder_id) } - pub fn resolve_regions_and_report_errors(&self) { - let errors = self.region_vars.resolve_regions(); - self.report_region_errors(&errors); // see error_reporting.rs + pub fn resolve_regions_and_report_errors( + &self, + loop_analysis: Option<&LoopAnalysis>) { + let errors = self.region_vars.resolve_regions(loop_analysis); + // See `error_reporting.rs`. + self.report_region_errors(&errors); } pub fn ty_to_string(&self, t: ty::t) -> String { @@ -808,9 +808,6 @@ impl<'a> InferCtxt<'a> { error_str).as_slice()); } } - for err in err.iter() { - ty::note_and_explain_type_err(self.tcx, *err) - } } } @@ -872,7 +869,7 @@ impl<'a> InferCtxt<'a> { pub fn fold_regions_in_sig(tcx: &ty::ctxt, fn_sig: &ty::FnSig, - fldr: |r: ty::Region| -> ty::Region) + fldr: |r: &ty::Region| -> ty::Region) -> ty::FnSig { ty_fold::RegionFolder::regions(tcx, fldr).fold_sig(fn_sig) } diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index f34894346f64a..33211c1d36571 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -10,11 +10,12 @@ /*! See doc.rs */ - +use middle::loop_analysis::LoopAnalysis; +use middle::seme_region::SemeRegion; use middle::ty; use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid}; use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound}; -use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; +use middle::ty::{ReLateBound, ReSemeRegion, ReVar, ReSkolemized, BrFresh}; use middle::typeck::infer::cres; use middle::typeck::infer::{RegionVariableOrigin, SubregionOrigin, TypeTrace}; use middle::typeck::infer; @@ -31,7 +32,7 @@ use syntax::ast; mod doc; // A constraint that influences the inference process. -#[deriving(PartialEq, Eq, Hash)] +#[deriving(PartialEq, Eq, Hash, Clone)] pub enum Constraint { // One region variable is subregion of another ConstrainVarSubVar(RegionVid, RegionVid), @@ -58,7 +59,7 @@ pub enum Verify { VerifyParamBound(ty::ParamTy, SubregionOrigin, Region, Vec), } -#[deriving(PartialEq, Eq, Hash)] +#[deriving(PartialEq, Eq, Hash, Clone)] pub struct TwoRegions { a: Region, b: Region, @@ -367,7 +368,7 @@ impl<'a> RegionVarBindings<'a> { debug!("RegionVarBindings: add_constraint({})", constraint.repr(self.tcx)); - if self.constraints.borrow_mut().insert(constraint, origin) { + if self.constraints.borrow_mut().insert(constraint.clone(), origin) { if self.in_snapshot() { self.undo_log.borrow_mut().push(AddConstraint(constraint)); } @@ -408,8 +409,8 @@ impl<'a> RegionVarBindings<'a> { pub fn make_eqregion(&self, origin: SubregionOrigin, - sub: Region, - sup: Region) { + sub: &Region, + sup: &Region) { if sub != sup { // Eventually, it would be nice to add direct support for // equating regions. @@ -420,8 +421,8 @@ impl<'a> RegionVarBindings<'a> { pub fn make_subregion(&self, origin: SubregionOrigin, - sub: Region, - sup: Region) { + sub: &Region, + sup: &Region) { // cannot add constraints once regions are resolved assert!(self.values_are_none()); @@ -431,37 +432,43 @@ impl<'a> RegionVarBindings<'a> { origin.repr(self.tcx)); match (sub, sup) { - (ReEarlyBound(..), ReEarlyBound(..)) => { + (&ReEarlyBound(..), &ReEarlyBound(..)) => { // This case is used only to make sure that explicitly-specified // `Self` types match the real self type in implementations. // // FIXME(NDM) -- we really shouldn't be comparing bound things - self.add_verify(VerifyRegSubReg(origin, sub, sup)); + self.add_verify(VerifyRegSubReg(origin, + (*sub).clone(), + (*sup).clone())); } - (ReEarlyBound(..), _) | - (ReLateBound(..), _) | - (_, ReEarlyBound(..)) | - (_, ReLateBound(..)) => { + (&ReEarlyBound(..), _) | + (&ReLateBound(..), _) | + (_, &ReEarlyBound(..)) | + (_, &ReLateBound(..)) => { self.tcx.sess.span_bug( origin.span(), format!("cannot relate bound region: {} <= {}", sub.repr(self.tcx), sup.repr(self.tcx)).as_slice()); } - (_, ReStatic) => { + (_, &ReStatic) => { // all regions are subregions of static, so we can ignore this } - (ReInfer(ReVar(sub_id)), ReInfer(ReVar(sup_id))) => { + (&ReInfer(ReVar(sub_id)), &ReInfer(ReVar(sup_id))) => { self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin); } - (r, ReInfer(ReVar(sup_id))) => { - self.add_constraint(ConstrainRegSubVar(r, sup_id), origin); + (r, &ReInfer(ReVar(sup_id))) => { + self.add_constraint(ConstrainRegSubVar((*r).clone(), sup_id), + origin); } - (ReInfer(ReVar(sub_id)), r) => { - self.add_constraint(ConstrainVarSubReg(sub_id, r), origin); + (&ReInfer(ReVar(sub_id)), r) => { + self.add_constraint(ConstrainVarSubReg(sub_id, (*r).clone()), + origin); } _ => { - self.add_verify(VerifyRegSubReg(origin, sub, sup)); + self.add_verify(VerifyRegSubReg(origin, + (*sub).clone(), + (*sup).clone())); } } } @@ -469,15 +476,18 @@ impl<'a> RegionVarBindings<'a> { pub fn verify_param_bound(&self, origin: SubregionOrigin, param_ty: ty::ParamTy, - sub: Region, + sub: &Region, sups: Vec) { - self.add_verify(VerifyParamBound(param_ty, origin, sub, sups)); + self.add_verify(VerifyParamBound(param_ty, + origin, + (*sub).clone(), + sups)); } pub fn lub_regions(&self, origin: SubregionOrigin, - a: Region, - b: Region) + a: &Region, + b: &Region) -> Region { // cannot add constraints once regions are resolved assert!(self.values_are_none()); @@ -486,7 +496,7 @@ impl<'a> RegionVarBindings<'a> { a.repr(self.tcx), b.repr(self.tcx)); match (a, b) { - (ReStatic, _) | (_, ReStatic) => { + (&ReStatic, _) | (_, &ReStatic) => { ReStatic // nothing lives longer than static } @@ -499,10 +509,11 @@ impl<'a> RegionVarBindings<'a> { } } - pub fn glb_regions(&self, + pub fn glb_regions<'a>( + &self, origin: SubregionOrigin, - a: Region, - b: Region) + a: &'a Region, + b: &'a Region) -> Region { // cannot add constraints once regions are resolved assert!(self.values_are_none()); @@ -511,9 +522,9 @@ impl<'a> RegionVarBindings<'a> { a.repr(self.tcx), b.repr(self.tcx)); match (a, b) { - (ReStatic, r) | (r, ReStatic) => { + (&ReStatic, r) | (r, &ReStatic) => { // static lives longer than everything else - r + (*r).clone() } _ => { @@ -526,11 +537,11 @@ impl<'a> RegionVarBindings<'a> { } pub fn max_regions(&self, - a: Region, - b: Region) - -> Option - { - match self.glb_concrete_regions(a, b) { + loop_analysis: Option<&LoopAnalysis>, + a: &Region, + b: &Region) + -> Option { + match self.glb_concrete_regions(loop_analysis, a, b) { Ok(r) => Some(r), Err(_) => None } @@ -562,14 +573,17 @@ impl<'a> RegionVarBindings<'a> { pub fn combine_vars(&self, t: CombineMapType, - a: Region, - b: Region, + a: &Region, + b: &Region, origin: SubregionOrigin, relate: |this: &RegionVarBindings, - old_r: Region, - new_r: Region|) + old_r: &Region, + new_r: &Region|) -> Region { - let vars = TwoRegions { a: a, b: b }; + let vars = TwoRegions { + a: (*a).clone(), + b: (*b).clone(), + }; match self.combine_map(t).borrow().find(&vars) { Some(&c) => { return ReInfer(ReVar(c)); @@ -577,12 +591,12 @@ impl<'a> RegionVarBindings<'a> { None => {} } let c = self.new_region_var(infer::MiscVariable(origin.span())); - self.combine_map(t).borrow_mut().insert(vars, c); + self.combine_map(t).borrow_mut().insert(vars.clone(), c); if self.in_snapshot() { self.undo_log.borrow_mut().push(AddCombination(t, vars)); } - relate(self, a, ReInfer(ReVar(c))); - relate(self, b, ReInfer(ReVar(c))); + relate(self, a, &ReInfer(ReVar(c))); + relate(self, b, &ReInfer(ReVar(c))); debug!("combine_vars() c={}", c); ReInfer(ReVar(c)) } @@ -593,14 +607,14 @@ impl<'a> RegionVarBindings<'a> { self.undo_log.borrow() .slice_from(mark.length) .iter() - .filter_map(|&elt| match elt { + .filter_map(|elt| match *elt { AddVar(vid) => Some(vid), _ => None }) .collect() } - pub fn tainted(&self, mark: RegionMark, r0: Region) -> Vec { + pub fn tainted(&self, mark: RegionMark, r0: &Region) -> Vec { /*! * Computes all regions that have been related to `r0` in any * way since the mark `mark` was made---`r0` itself will be @@ -615,11 +629,11 @@ impl<'a> RegionVarBindings<'a> { // `result_set` acts as a worklist: we explore all outgoing // edges and add any new regions we find to result_set. This // is not a terribly efficient implementation. - let mut result_set = vec!(r0); + let mut result_set = vec!((*r0).clone()); let mut result_index = 0; while result_index < result_set.len() { // nb: can't use uint::range() here because result_set grows - let r = *result_set.get(result_index); + let r = (*result_set.get(result_index)).clone(); debug!("result_index={}, r={}", result_index, r); for undo_entry in @@ -628,36 +642,48 @@ impl<'a> RegionVarBindings<'a> { match undo_entry { &AddConstraint(ConstrainVarSubVar(a, b)) => { consider_adding_bidirectional_edges( - &mut result_set, r, - ReInfer(ReVar(a)), ReInfer(ReVar(b))); + &mut result_set, + &r, + &ReInfer(ReVar(a)), + &ReInfer(ReVar(b))); } - &AddConstraint(ConstrainRegSubVar(a, b)) => { + &AddConstraint(ConstrainRegSubVar(ref a, b)) => { consider_adding_bidirectional_edges( - &mut result_set, r, - a, ReInfer(ReVar(b))); + &mut result_set, + &r, + a, + &ReInfer(ReVar(b))); } - &AddConstraint(ConstrainVarSubReg(a, b)) => { + &AddConstraint(ConstrainVarSubReg(a, ref b)) => { consider_adding_bidirectional_edges( - &mut result_set, r, - ReInfer(ReVar(a)), b); + &mut result_set, + &r, + &ReInfer(ReVar(a)), + b); } &AddGiven(a, b) => { consider_adding_bidirectional_edges( - &mut result_set, r, - ReFree(a), ReInfer(ReVar(b))); + &mut result_set, + &r, + &ReFree(a), + &ReInfer(ReVar(b))); } &AddVerify(i) => { match self.verifys.borrow().get(i) { - &VerifyRegSubReg(_, a, b) => { + &VerifyRegSubReg(_, ref a, ref b) => { consider_adding_bidirectional_edges( - &mut result_set, r, - a, b); + &mut result_set, + &r, + a, + b); } - &VerifyParamBound(_, _, a, ref bs) => { - for &b in bs.iter() { + &VerifyParamBound(_, _, ref a, ref bs) => { + for b in bs.iter() { consider_adding_bidirectional_edges( - &mut result_set, r, - a, b); + &mut result_set, + &r, + a, + b); } } } @@ -677,21 +703,21 @@ impl<'a> RegionVarBindings<'a> { return result_set; fn consider_adding_bidirectional_edges(result_set: &mut Vec, - r: Region, - r1: Region, - r2: Region) { + r: &Region, + r1: &Region, + r2: &Region) { consider_adding_directed_edge(result_set, r, r1, r2); consider_adding_directed_edge(result_set, r, r2, r1); } fn consider_adding_directed_edge(result_set: &mut Vec, - r: Region, - r1: Region, - r2: Region) { + r: &Region, + r1: &Region, + r2: &Region) { if r == r1 { // Clearly, this is potentially inefficient. - if !result_set.iter().any(|x| *x == r2) { - result_set.push(r2); + if !result_set.iter().any(|x| *x == *r2) { + result_set.push((*r2).clone()); } } } @@ -704,41 +730,47 @@ impl<'a> RegionVarBindings<'a> { constraints, assuming such values can be found; if they cannot, errors are reported. */ - pub fn resolve_regions(&self) -> Vec { + pub fn resolve_regions(&self, loop_analysis: Option<&LoopAnalysis>) + -> Vec { debug!("RegionVarBindings: resolve_regions()"); let mut errors = vec!(); - let v = self.infer_variable_values(&mut errors); + let v = self.infer_variable_values(loop_analysis, &mut errors); *self.values.borrow_mut() = Some(v); errors } } impl<'a> RegionVarBindings<'a> { - fn is_subregion_of(&self, sub: Region, sup: Region) -> bool { - self.tcx.region_maps.is_subregion_of(sub, sup) + fn is_subregion_of(&self, sub: &Region, sup: &Region) -> bool { + self.tcx.region_maps.is_subregion_of(self.tcx, sub, sup) } - fn lub_concrete_regions(&self, a: Region, b: Region) -> Region { + fn lub_concrete_regions<'a>( + &self, + loop_analysis: Option<&LoopAnalysis>, + a: &'a Region, + b: &'a Region) + -> Region { match (a, b) { - (ReLateBound(..), _) | - (_, ReLateBound(..)) | - (ReEarlyBound(..), _) | - (_, ReEarlyBound(..)) => { + (&ReLateBound(..), _) | + (_, &ReLateBound(..)) | + (&ReEarlyBound(..), _) | + (_, &ReEarlyBound(..)) => { self.tcx.sess.bug( format!("cannot relate bound region: LUB({}, {})", a.repr(self.tcx), b.repr(self.tcx)).as_slice()); } - (ReStatic, _) | (_, ReStatic) => { + (&ReStatic, _) | (_, &ReStatic) => { ReStatic // nothing lives longer than static } - (ReEmpty, r) | (r, ReEmpty) => { - r // everything lives longer than empty + (&ReEmpty, r) | (r, &ReEmpty) => { + (*r).clone() // everything lives longer than empty } - (ReInfer(ReVar(v_id)), _) | (_, ReInfer(ReVar(v_id))) => { + (&ReInfer(ReVar(v_id)), _) | (_, &ReInfer(ReVar(v_id))) => { self.tcx.sess.span_bug( self.var_origins.borrow().get(v_id.index).span(), format!("lub_concrete_regions invoked with \ @@ -747,13 +779,16 @@ impl<'a> RegionVarBindings<'a> { b).as_slice()); } - (ReFree(ref fr), ReScope(s_id)) | - (ReScope(s_id), ReFree(ref fr)) => { + (&ReFree(ref fr), &ReSemeRegion(ref s_seme_region)) | + (&ReSemeRegion(ref s_seme_region), &ReFree(ref fr)) => { + let s_id = s_seme_region.lub_scope(self.tcx); let f = ReFree(*fr); // A "free" region can be interpreted as "some region // at least as big as the block fr.scope_id". So, we can // reasonably compare free regions and scopes: - match self.tcx.region_maps.nearest_common_ancestor(fr.scope_id, s_id) { + match self.tcx + .region_maps + .nearest_common_ancestor(fr.scope_id, s_id) { // if the free region's scope `fr.scope_id` is bigger than // the scope region `s_id`, then the LUB is the free // region itself: @@ -765,33 +800,45 @@ impl<'a> RegionVarBindings<'a> { } } - (ReScope(a_id), ReScope(b_id)) => { - // The region corresponding to an outer block is a - // subtype of the region corresponding to an inner - // block. - match self.tcx.region_maps.nearest_common_ancestor(a_id, b_id) { - Some(r_id) => ReScope(r_id), - _ => ReStatic + (&ReSemeRegion(ref a_seme_region), + &ReSemeRegion(ref b_seme_region)) => { + match loop_analysis { + None => { + self.tcx + .sess + .bug("RegionVarBindings::lub_concrete_regions(): \ + cannot relate SEME regions if no loop \ + analysis present") + } + Some(loop_analysis) => { + match a_seme_region.lub(b_seme_region, + self.tcx, + loop_analysis) { + Some(seme_region) => ReSemeRegion(seme_region), + None => ReStatic, + } + } } } - (ReFree(ref a_fr), ReFree(ref b_fr)) => { + (&ReFree(ref a_fr), &ReFree(ref b_fr)) => { self.lub_free_regions(a_fr, b_fr) } // For these types, we cannot define any additional // relationship: - (ReInfer(ReSkolemized(..)), _) | - (_, ReInfer(ReSkolemized(..))) => { - if a == b {a} else {ReStatic} + (&ReInfer(ReSkolemized(..)), _) | + (_, &ReInfer(ReSkolemized(..))) => { + if a == b { + (*a).clone() + } else { + ReStatic + } } } } - fn lub_free_regions(&self, - a: &FreeRegion, - b: &FreeRegion) -> ty::Region - { + fn lub_free_regions(&self, a: &FreeRegion, b: &FreeRegion) -> ty::Region { /*! * Computes a region that encloses both free region arguments. * Guarantee that if the same two regions are given as argument, @@ -818,34 +865,38 @@ impl<'a> RegionVarBindings<'a> { } } - fn glb_concrete_regions(&self, - a: Region, - b: Region) - -> cres { - debug!("glb_concrete_regions({}, {})", a, b); + fn glb_concrete_regions<'a>( + &self, + loop_analysis: Option<&LoopAnalysis>, + a: &'a Region, + b: &'a Region) + -> cres { + debug!("glb_concrete_regions({}, {})", + a.repr(self.tcx), + b.repr(self.tcx)); match (a, b) { - (ReLateBound(..), _) | - (_, ReLateBound(..)) | - (ReEarlyBound(..), _) | - (_, ReEarlyBound(..)) => { + (&ReLateBound(..), _) | + (_, &ReLateBound(..)) | + (&ReEarlyBound(..), _) | + (_, &ReEarlyBound(..)) => { self.tcx.sess.bug( format!("cannot relate bound region: GLB({}, {})", a.repr(self.tcx), b.repr(self.tcx)).as_slice()); } - (ReStatic, r) | (r, ReStatic) => { + (&ReStatic, r) | (r, &ReStatic) => { // static lives longer than everything else - Ok(r) + Ok((*r).clone()) } - (ReEmpty, _) | (_, ReEmpty) => { + (&ReEmpty, _) | (_, &ReEmpty) => { // nothing lives shorter than everything else Ok(ReEmpty) } - (ReInfer(ReVar(v_id)), _) | - (_, ReInfer(ReVar(v_id))) => { + (&ReInfer(ReVar(v_id)), _) | + (_, &ReInfer(ReVar(v_id))) => { self.tcx.sess.span_bug( self.var_origins.borrow().get(v_id.index).span(), format!("glb_concrete_regions invoked with \ @@ -854,45 +905,77 @@ impl<'a> RegionVarBindings<'a> { b).as_slice()); } - (ReFree(ref fr), ReScope(s_id)) | - (ReScope(s_id), ReFree(ref fr)) => { - let s = ReScope(s_id); + (&ReFree(ref fr), &ReSemeRegion(ref seme_region)) | + (&ReSemeRegion(ref seme_region), &ReFree(ref fr)) => { + let s = ReSemeRegion((*seme_region).clone()); + let s_id = seme_region.lub_scope(self.tcx); // Free region is something "at least as big as - // `fr.scope_id`." If we find that the scope `fr.scope_id` is bigger - // than the scope `s_id`, then we can say that the GLB - // is the scope `s_id`. Otherwise, as we do not know - // big the free region is precisely, the GLB is undefined. - match self.tcx.region_maps.nearest_common_ancestor(fr.scope_id, s_id) { + // `fr.scope_id`." If we find that the scope + // `fr.scope_id` is bigger than the scope `s_id`, then + // we can say that the GLB is the scope `s_id`. + // Otherwise, as we do not know big the free region is + // precisely, the GLB is undefined. + match self.tcx + .region_maps + .nearest_common_ancestor(fr.scope_id, + s_id) { Some(r_id) if r_id == fr.scope_id => Ok(s), - _ => Err(ty::terr_regions_no_overlap(b, a)) + _ => { + Err(ty::terr_regions_no_overlap((*b).clone(), + (*a).clone())) + } } } - (ReScope(a_id), ReScope(b_id)) => { - self.intersect_scopes(a, b, a_id, b_id) + (&ReSemeRegion(ref a_seme_region), + &ReSemeRegion(ref b_seme_region)) => { + match loop_analysis { + None => { + self.tcx + .sess + .bug("RegionVarBindings::glb_concrete_regions(): \ + cannot relate SEME regions if no loop \ + analysis present") + } + Some(loop_analysis) => { + match a_seme_region.glb(b_seme_region, + self.tcx, + loop_analysis) { + Some(seme_region) => { + Ok(ReSemeRegion(seme_region)) + } + None => { + Err(ty::terr_regions_no_overlap((*a).clone(), + (*b).clone())) + } + } + } + } } - (ReFree(ref a_fr), ReFree(ref b_fr)) => { - self.glb_free_regions(a_fr, b_fr) + (&ReFree(ref a_fr), &ReFree(ref b_fr)) => { + self.glb_free_regions(loop_analysis, a_fr, b_fr) } // For these types, we cannot define any additional // relationship: - (ReInfer(ReSkolemized(..)), _) | - (_, ReInfer(ReSkolemized(..))) => { + (&ReInfer(ReSkolemized(..)), _) | + (_, &ReInfer(ReSkolemized(..))) => { if a == b { - Ok(a) + Ok((*a).clone()) } else { - Err(ty::terr_regions_no_overlap(b, a)) + Err(ty::terr_regions_no_overlap((*b).clone(), + (*a).clone())) } } } } fn glb_free_regions(&self, + loop_analysis: Option<&LoopAnalysis>, a: &FreeRegion, - b: &FreeRegion) -> cres - { + b: &FreeRegion) + -> cres { /*! * Computes a region that is enclosed by both free region arguments, * if any. Guarantees that if the same two regions are given as argument, @@ -900,32 +983,42 @@ impl<'a> RegionVarBindings<'a> { */ return match a.cmp(b) { - Less => helper(self, a, b), - Greater => helper(self, b, a), + Less => helper(self, loop_analysis, a, b), + Greater => helper(self, loop_analysis, b, a), Equal => Ok(ty::ReFree(*a)) }; fn helper(this: &RegionVarBindings, + loop_analysis: Option<&LoopAnalysis>, a: &FreeRegion, - b: &FreeRegion) -> cres - { + b: &FreeRegion) + -> cres { if this.tcx.region_maps.sub_free_region(*a, *b) { Ok(ty::ReFree(*a)) } else if this.tcx.region_maps.sub_free_region(*b, *a) { Ok(ty::ReFree(*b)) } else { - this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b), - a.scope_id, b.scope_id) + match loop_analysis { + None => Ok(ReSemeRegion(SemeRegion::dummy())), + Some(loop_analysis) => { + this.intersect_scopes(loop_analysis, + &ty::ReFree(*a), + &ty::ReFree(*b), + a.scope_id, + b.scope_id) + } + } } } } fn intersect_scopes(&self, - region_a: ty::Region, - region_b: ty::Region, + loop_analysis: &LoopAnalysis, + region_a: &ty::Region, + region_b: &ty::Region, scope_a: ast::NodeId, - scope_b: ast::NodeId) -> cres - { + scope_b: ast::NodeId) + -> cres { // We want to generate the intersection of two // scopes or two free regions. So, if one of // these scopes is a subscope of the other, return @@ -933,9 +1026,20 @@ impl<'a> RegionVarBindings<'a> { debug!("intersect_scopes(scope_a={}, scope_b={}, region_a={}, region_b={})", scope_a, scope_b, region_a, region_b); match self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_b) { - Some(r_id) if scope_a == r_id => Ok(ReScope(scope_b)), - Some(r_id) if scope_b == r_id => Ok(ReScope(scope_a)), - _ => Err(ty::terr_regions_no_overlap(region_a, region_b)) + Some(r_id) if scope_a == r_id => { + Ok(ReSemeRegion(SemeRegion::from_scope(self.tcx, + loop_analysis, + scope_b))) + } + Some(r_id) if scope_b == r_id => { + Ok(ReSemeRegion(SemeRegion::from_scope(self.tcx, + loop_analysis, + scope_a))) + } + _ => { + Err(ty::terr_regions_no_overlap((*region_a).clone(), + (*region_b).clone())) + } } } } @@ -945,7 +1049,12 @@ impl<'a> RegionVarBindings<'a> { #[deriving(PartialEq, Show)] enum Classification { Expanding, Contracting } -pub enum VarValue { NoValue, Value(Region), ErrorValue } +#[deriving(Clone)] +pub enum VarValue { + NoValue, + Value(Region), + ErrorValue, +} struct VarData { classification: Classification, @@ -961,14 +1070,15 @@ type RegionGraph = graph::Graph<(), Constraint>; impl<'a> RegionVarBindings<'a> { fn infer_variable_values(&self, + loop_analysis: Option<&LoopAnalysis>, errors: &mut Vec) - -> Vec - { + -> Vec { let mut var_data = self.construct_var_data(); - self.expansion(var_data.as_mut_slice()); - self.contraction(var_data.as_mut_slice()); + self.expansion(loop_analysis, var_data.as_mut_slice()); + self.contraction(loop_analysis, var_data.as_mut_slice()); let values = - self.extract_values_and_collect_conflicts(var_data.as_slice(), + self.extract_values_and_collect_conflicts(loop_analysis, + var_data.as_slice(), errors); self.collect_concrete_region_errors(&values, errors); values @@ -987,7 +1097,9 @@ impl<'a> RegionVarBindings<'a> { }) } - fn expansion(&self, var_data: &mut [VarData]) { + fn expansion(&self, + loop_analysis: Option<&LoopAnalysis>, + var_data: &mut [VarData]) { self.iterate_until_fixed_point("Expansion", |constraint| { debug!("expansion: constraint={} origin={}", constraint.repr(self.tcx), @@ -996,16 +1108,16 @@ impl<'a> RegionVarBindings<'a> { .unwrap() .repr(self.tcx)); match *constraint { - ConstrainRegSubVar(a_region, b_vid) => { + ConstrainRegSubVar(ref a_region, b_vid) => { let b_data = &mut var_data[b_vid.index]; - self.expand_node(a_region, b_vid, b_data) + self.expand_node(loop_analysis, a_region, b_vid, b_data) } ConstrainVarSubVar(a_vid, b_vid) => { - match var_data[a_vid.index].value { + match var_data[a_vid.index].value.clone() { NoValue | ErrorValue => false, Value(a_region) => { let b_node = &mut var_data[b_vid.index]; - self.expand_node(a_region, b_vid, b_node) + self.expand_node(loop_analysis, &a_region, b_vid, b_node) } } } @@ -1018,18 +1130,18 @@ impl<'a> RegionVarBindings<'a> { } fn expand_node(&self, - a_region: Region, + loop_analysis: Option<&LoopAnalysis>, + a_region: &Region, b_vid: RegionVid, b_data: &mut VarData) - -> bool - { + -> bool { debug!("expand_node({}, {} == {})", a_region.repr(self.tcx), b_vid, b_data.value.repr(self.tcx)); // Check if this relationship is implied by a given. - match a_region { + match *a_region { ty::ReFree(fr) => { if self.givens.borrow().contains(&(fr, b_vid)) { debug!("given"); @@ -1040,18 +1152,23 @@ impl<'a> RegionVarBindings<'a> { } b_data.classification = Expanding; + + let lub; match b_data.value { NoValue => { debug!("Setting initial value of {} to {}", - b_vid, a_region.repr(self.tcx)); + b_vid, + a_region.repr(self.tcx)); - b_data.value = Value(a_region); + b_data.value = Value((*a_region).clone()); return true; } - Value(cur_region) => { - let lub = self.lub_concrete_regions(a_region, cur_region); - if lub == cur_region { + Value(ref cur_region) => { + lub = self.lub_concrete_regions(loop_analysis, + a_region, + cur_region); + if lub == *cur_region { return false; } @@ -1059,18 +1176,20 @@ impl<'a> RegionVarBindings<'a> { b_vid, cur_region.repr(self.tcx), lub.repr(self.tcx)); - - b_data.value = Value(lub); - return true; + // Jump out... } ErrorValue => { return false; } } + + b_data.value = Value(lub); + return true; } fn contraction(&self, + loop_analysis: Option<&LoopAnalysis>, var_data: &mut [VarData]) { self.iterate_until_fixed_point("Contraction", |constraint| { debug!("contraction: constraint={} origin={}", @@ -1085,35 +1204,41 @@ impl<'a> RegionVarBindings<'a> { false } ConstrainVarSubVar(a_vid, b_vid) => { - match var_data[b_vid.index].value { + match var_data[b_vid.index].value.clone() { NoValue | ErrorValue => false, Value(b_region) => { let a_data = &mut var_data[a_vid.index]; - self.contract_node(a_vid, a_data, b_region) + self.contract_node(loop_analysis, + a_vid, + a_data, + &b_region) } } } - ConstrainVarSubReg(a_vid, b_region) => { + ConstrainVarSubReg(a_vid, ref b_region) => { let a_data = &mut var_data[a_vid.index]; - self.contract_node(a_vid, a_data, b_region) + self.contract_node(loop_analysis, a_vid, a_data, b_region) } } }) } fn contract_node(&self, + loop_analysis: Option<&LoopAnalysis>, a_vid: RegionVid, a_data: &mut VarData, - b_region: Region) + b_region: &Region) -> bool { debug!("contract_node({} == {}/{}, {})", - a_vid, a_data.value.repr(self.tcx), - a_data.classification, b_region.repr(self.tcx)); + a_vid, + a_data.value.repr(self.tcx), + a_data.classification, + b_region.repr(self.tcx)); - return match a_data.value { + return match a_data.value.clone() { NoValue => { assert_eq!(a_data.classification, Contracting); - a_data.value = Value(b_region); + a_data.value = Value((*b_region).clone()); true // changed } @@ -1124,10 +1249,19 @@ impl<'a> RegionVarBindings<'a> { Value(a_region) => { match a_data.classification { Expanding => { - check_node(self, a_vid, a_data, a_region, b_region) + check_node(self, + a_vid, + a_data, + &a_region, + b_region) } Contracting => { - adjust_node(self, a_vid, a_data, a_region, b_region) + adjust_node(self, + loop_analysis, + a_vid, + a_data, + &a_region, + b_region) } } } @@ -1136,9 +1270,9 @@ impl<'a> RegionVarBindings<'a> { fn check_node(this: &RegionVarBindings, a_vid: RegionVid, a_data: &mut VarData, - a_region: Region, - b_region: Region) - -> bool { + a_region: &Region, + b_region: &Region) + -> bool { if !this.is_subregion_of(a_region, b_region) { debug!("Setting {} to ErrorValue: {} not subregion of {}", a_vid, @@ -1150,14 +1284,17 @@ impl<'a> RegionVarBindings<'a> { } fn adjust_node(this: &RegionVarBindings, + loop_analysis: Option<&LoopAnalysis>, a_vid: RegionVid, a_data: &mut VarData, - a_region: Region, - b_region: Region) + a_region: &Region, + b_region: &Region) -> bool { - match this.glb_concrete_regions(a_region, b_region) { + match this.glb_concrete_regions(loop_analysis, + a_region, + b_region) { Ok(glb) => { - if glb == a_region { + if glb == *a_region { false } else { debug!("Contracting value of {} from {} to {}", @@ -1180,14 +1317,14 @@ impl<'a> RegionVarBindings<'a> { } } - fn collect_concrete_region_errors(&self, - values: &Vec, - errors: &mut Vec) - { + fn collect_concrete_region_errors( + &self, + values: &Vec, + errors: &mut Vec) { let mut reg_reg_dups = HashSet::new(); for verify in self.verifys.borrow().iter() { match *verify { - VerifyRegSubReg(ref origin, sub, sup) => { + VerifyRegSubReg(ref origin, ref sub, ref sup) => { if self.is_subregion_of(sub, sup) { continue; } @@ -1199,20 +1336,25 @@ impl<'a> RegionVarBindings<'a> { debug!("ConcreteFailure: !(sub <= sup): sub={}, sup={}", sub.repr(self.tcx), sup.repr(self.tcx)); - errors.push(ConcreteFailure((*origin).clone(), sub, sup)); + errors.push(ConcreteFailure((*origin).clone(), + (*sub).clone(), + (*sup).clone())); } - VerifyParamBound(ref param_ty, ref origin, sub, ref sups) => { + VerifyParamBound(ref param_ty, + ref origin, + ref sub, + ref sups) => { let sub = normalize(values, sub); if sups.iter() - .map(|&sup| normalize(values, sup)) - .any(|sup| self.is_subregion_of(sub, sup)) - { + .map(|sup| normalize(values, sup)) + .any(|sup| self.is_subregion_of(&sub, &sup)) { continue; } - let sups = sups.iter().map(|&sup| normalize(values, sup)) - .collect(); + let sups = sups.iter() + .map(|sup| normalize(values, sup)) + .collect(); errors.push( ParamBoundFailure( (*origin).clone(), *param_ty, sub, sups)); @@ -1222,11 +1364,11 @@ impl<'a> RegionVarBindings<'a> { } fn extract_values_and_collect_conflicts( - &self, - var_data: &[VarData], - errors: &mut Vec) - -> Vec - { + &self, + loop_analysis: Option<&LoopAnalysis>, + var_data: &[VarData], + errors: &mut Vec) + -> Vec { debug!("extract_values_and_collect_conflicts()"); // This is the best way that I have found to suppress @@ -1288,20 +1430,27 @@ impl<'a> RegionVarBindings<'a> { match var_data[idx].classification { Expanding => { self.collect_error_for_expanding_node( - graph, var_data, dup_vec.as_mut_slice(), - node_vid, errors); + graph, + var_data, + dup_vec.as_mut_slice(), + node_vid, + errors); } Contracting => { self.collect_error_for_contracting_node( - graph, var_data, dup_vec.as_mut_slice(), - node_vid, errors); + loop_analysis, + graph, + var_data, + dup_vec.as_mut_slice(), + node_vid, + errors); } } } } } - Vec::from_fn(self.num_vars(), |idx| var_data[idx].value) + Vec::from_fn(self.num_vars(), |idx| var_data[idx].value.clone()) } fn construct_graph(&self) -> RegionGraph { @@ -1323,17 +1472,17 @@ impl<'a> RegionVarBindings<'a> { ConstrainVarSubVar(a_id, b_id) => { graph.add_edge(NodeIndex(a_id.index), NodeIndex(b_id.index), - *constraint); + (*constraint).clone()); } ConstrainRegSubVar(_, b_id) => { graph.add_edge(dummy_idx, NodeIndex(b_id.index), - *constraint); + (*constraint).clone()); } ConstrainVarSubReg(a_id, _) => { graph.add_edge(NodeIndex(a_id.index), dummy_idx, - *constraint); + (*constraint).clone()); } } } @@ -1347,8 +1496,7 @@ impl<'a> RegionVarBindings<'a> { var_data: &[VarData], dup_vec: &mut [uint], node_idx: RegionVid, - errors: &mut Vec) - { + errors: &mut Vec) { // Errors in expanding nodes result from a lower-bound that is // not contained by an upper-bound. let (mut lower_bounds, lower_dup) = @@ -1368,10 +1516,10 @@ impl<'a> RegionVarBindings<'a> { fn free_regions_first(a: &RegionAndOrigin, b: &RegionAndOrigin) -> Ordering { - match (a.region, b.region) { - (ReFree(..), ReFree(..)) => Equal, - (ReFree(..), _) => Less, - (_, ReFree(..)) => Greater, + match (&a.region, &b.region) { + (&ReFree(..), &ReFree(..)) => Equal, + (&ReFree(..), _) => Less, + (_, &ReFree(..)) => Greater, (_, _) => Equal, } } @@ -1380,14 +1528,14 @@ impl<'a> RegionVarBindings<'a> { for lower_bound in lower_bounds.iter() { for upper_bound in upper_bounds.iter() { - if !self.is_subregion_of(lower_bound.region, - upper_bound.region) { + if !self.is_subregion_of(&lower_bound.region, + &upper_bound.region) { errors.push(SubSupConflict( self.var_origins.borrow().get(node_idx.index).clone(), lower_bound.origin.clone(), - lower_bound.region, + lower_bound.region.clone(), upper_bound.origin.clone(), - upper_bound.region)); + upper_bound.region.clone())); return; } } @@ -1398,18 +1546,24 @@ impl<'a> RegionVarBindings<'a> { format!("collect_error_for_expanding_node() could not find error \ for var {}, lower_bounds={}, upper_bounds={}", node_idx, - lower_bounds.repr(self.tcx), - upper_bounds.repr(self.tcx)).as_slice()); + lower_bounds.iter() + .map(|x| x.region.clone()) + .collect::>() + .repr(self.tcx), + upper_bounds.iter() + .map(|x| x.region.clone()) + .collect::>() + .repr(self.tcx)).as_slice()); } fn collect_error_for_contracting_node( &self, + loop_analysis: Option<&LoopAnalysis>, graph: &RegionGraph, var_data: &[VarData], dup_vec: &mut [uint], node_idx: RegionVid, - errors: &mut Vec) - { + errors: &mut Vec) { // Errors in contracting nodes result from two upper-bounds // that have no intersection. let (upper_bounds, dup_found) = @@ -1422,16 +1576,17 @@ impl<'a> RegionVarBindings<'a> { for upper_bound_1 in upper_bounds.iter() { for upper_bound_2 in upper_bounds.iter() { - match self.glb_concrete_regions(upper_bound_1.region, - upper_bound_2.region) { + match self.glb_concrete_regions(loop_analysis, + &upper_bound_1.region, + &upper_bound_2.region) { Ok(_) => {} Err(_) => { errors.push(SupSupConflict( self.var_origins.borrow().get(node_idx.index).clone(), upper_bound_1.origin.clone(), - upper_bound_1.region, + upper_bound_1.region.clone(), upper_bound_2.origin.clone(), - upper_bound_2.region)); + upper_bound_2.region.clone())); return; } } @@ -1440,10 +1595,13 @@ impl<'a> RegionVarBindings<'a> { self.tcx.sess.span_bug( self.var_origins.borrow().get(node_idx.index).span(), - format!("collect_error_for_contracting_node() could not find error \ - for var {}, upper_bounds={}", + format!("collect_error_for_contracting_node() could not find \ + error for var {}, upper_bounds={}", node_idx, - upper_bounds.repr(self.tcx)).as_slice()); + upper_bounds.iter() + .map(|x| x.region.clone()) + .collect::>() + .repr(self.tcx)).as_slice()); } fn collect_concrete_regions(&self, @@ -1517,11 +1675,13 @@ impl<'a> RegionVarBindings<'a> { } } - ConstrainRegSubVar(region, _) | - ConstrainVarSubReg(_, region) => { + ConstrainRegSubVar(ref region, _) | + ConstrainVarSubReg(_, ref region) => { state.result.push(RegionAndOrigin { - region: region, - origin: this.constraints.borrow().get_copy(&edge.data) + region: (*region).clone(), + origin: this.constraints + .borrow() + .get_copy(&edge.data), }); } } @@ -1539,6 +1699,9 @@ impl<'a> RegionVarBindings<'a> { changed = false; iteration += 1; debug!("---- {} Iteration {}{}", "#", tag, iteration); + if iteration > 1000 { + self.tcx.sess.bug("infinite loop in regionck iteration") + } for (constraint, _) in self.constraints.borrow().iter() { let edge_changed = body(constraint); if edge_changed { @@ -1559,10 +1722,10 @@ impl Repr for Constraint { ConstrainVarSubVar(a, b) => { format!("ConstrainVarSubVar({}, {})", a.repr(tcx), b.repr(tcx)) } - ConstrainRegSubVar(a, b) => { + ConstrainRegSubVar(ref a, b) => { format!("ConstrainRegSubVar({}, {})", a.repr(tcx), b.repr(tcx)) } - ConstrainVarSubReg(a, b) => { + ConstrainVarSubReg(a, ref b) => { format!("ConstrainVarSubReg({}, {})", a.repr(tcx), b.repr(tcx)) } } @@ -1583,16 +1746,16 @@ impl Repr for Verify { } } -fn normalize(values: &Vec, r: ty::Region) -> ty::Region { - match r { +fn normalize(values: &Vec, r: &ty::Region) -> ty::Region { + match *r { ty::ReInfer(ReVar(rid)) => lookup(values, rid), - _ => r + _ => (*r).clone(), } } fn lookup(values: &Vec, rid: ty::RegionVid) -> ty::Region { match *values.get(rid.index) { - Value(r) => r, + Value(ref r) => (*r).clone(), NoValue => ReEmpty, // No constraints, return ty::ReEmpty ErrorValue => ReStatic, // Previously reported error. } @@ -1602,7 +1765,7 @@ impl Repr for VarValue { fn repr(&self, tcx: &ty::ctxt) -> String { match *self { NoValue => format!("NoValue"), - Value(r) => format!("Value({})", r.repr(tcx)), + Value(ref r) => format!("Value({})", r.repr(tcx)), ErrorValue => format!("ErrorValue"), } } diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/typeck/infer/resolve.rs index f9742c522dac4..8d6dc7a4fb616 100644 --- a/src/librustc/middle/typeck/infer/resolve.rs +++ b/src/librustc/middle/typeck/infer/resolve.rs @@ -104,7 +104,7 @@ impl<'a> ty_fold::TypeFolder for ResolveState<'a> { self.resolve_type(t) } - fn fold_region(&mut self, r: ty::Region) -> ty::Region { + fn fold_region(&mut self, r: &ty::Region) -> ty::Region { self.resolve_region(r) } } @@ -141,8 +141,7 @@ impl<'a> ResolveState<'a> { } } - pub fn resolve_region_chk(&mut self, - orig: ty::Region) + pub fn resolve_region_chk(&mut self, orig: &ty::Region) -> fres { self.err = None; let resolved = indent(|| self.resolve_region(orig) ); @@ -189,11 +188,11 @@ impl<'a> ResolveState<'a> { } } - pub fn resolve_region(&mut self, orig: ty::Region) -> ty::Region { + pub fn resolve_region(&mut self, orig: &ty::Region) -> ty::Region { debug!("Resolve_region({})", orig.repr(self.infcx.tcx)); - match orig { + match *orig { ty::ReInfer(ty::ReVar(rid)) => self.resolve_region_var(rid), - _ => orig + _ => (*orig).clone() } } diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index be4abb1ad8261..15d17f92d16c3 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -52,22 +52,24 @@ impl<'f> Combine for Sub<'f> { Sub(self.fields.switch_expected()).tys(b, a) } - fn contraregions(&self, a: ty::Region, b: ty::Region) - -> cres { - let opp = CombineFields { - a_is_expected: !self.fields.a_is_expected, - ..self.fields.clone() - }; - Sub(opp).regions(b, a) - } - - fn regions(&self, a: ty::Region, b: ty::Region) -> cres { + fn contraregions(&self, a: &ty::Region, b: &ty::Region) + -> cres { + let opp = CombineFields { + a_is_expected: !self.fields.a_is_expected, + ..self.fields.clone() + }; + Sub(opp).regions(b, a) + } + + fn regions(&self, a: &ty::Region, b: &ty::Region) -> cres { debug!("{}.regions({}, {})", self.tag(), a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx)); - self.fields.infcx.region_vars.make_subregion(Subtype(self.trace()), a, b); - Ok(a) + self.fields.infcx.region_vars.make_subregion(Subtype(self.trace()), + a, + b); + Ok((*a).clone()) } fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres { @@ -217,7 +219,7 @@ impl<'f> Combine for Sub<'f> { // that the skolemized regions do not "leak". let new_vars = self.fields.infcx.region_vars.vars_created_since_mark(mark); - for (&skol_br, &skol) in skol_map.iter() { + for (&skol_br, skol) in skol_map.iter() { let tainted = self.fields.infcx.region_vars.tainted(mark, skol); for tainted_region in tainted.iter() { // Each skolemized should only be relatable to itself @@ -227,7 +229,7 @@ impl<'f> Combine for Sub<'f> { if new_vars.iter().any(|x| x == vid) { continue; } } _ => { - if *tainted_region == skol { continue; } + if *tainted_region == *skol { continue; } } }; @@ -235,11 +237,13 @@ impl<'f> Combine for Sub<'f> { if self.a_is_expected() { debug!("Not as polymorphic!"); return Err(ty::terr_regions_insufficiently_polymorphic( - skol_br, *tainted_region)); + skol_br, + (*tainted_region).clone())); } else { debug!("Overly polymorphic!"); return Err(ty::terr_regions_overly_polymorphic( - skol_br, *tainted_region)); + skol_br, + (*tainted_region).clone())); } } } diff --git a/src/librustc/middle/typeck/infer/test.rs b/src/librustc/middle/typeck/infer/test.rs deleted file mode 100644 index dd00fc6207981..0000000000000 --- a/src/librustc/middle/typeck/infer/test.rs +++ /dev/null @@ -1,519 +0,0 @@ -// 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. - -/*! - -# Standalone Tests for the Inference Module - -*/ - -// This is only used by tests, hence allow dead code. -#![allow(dead_code)] - -use driver::config; -use driver::diagnostic; -use driver::diagnostic::Emitter; -use driver::driver; -use driver::session; -use middle::freevars; -use middle::lang_items; -use middle::region; -use middle::resolve; -use middle::resolve_lifetime; -use middle::stability; -use middle::ty; -use middle::typeck::infer::combine::Combine; -use middle::typeck::infer; -use middle::typeck::infer::lub::Lub; -use middle::typeck::infer::glb::Glb; -use syntax::codemap; -use syntax::codemap::{Span, CodeMap, DUMMY_SP}; -use syntax::diagnostic::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note}; -use syntax::ast; -use util::ppaux::{ty_to_string, UserString}; - -struct Env<'a> { - krate: ast::Crate, - tcx: &'a ty::ctxt, - infcx: &'a infer::InferCtxt<'a>, -} - -struct RH<'a> { - id: ast::NodeId, - sub: &'a [RH<'a>] -} - -static EMPTY_SOURCE_STR: &'static str = "#![no_std]"; - -struct ExpectErrorEmitter { - messages: Vec -} - -fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) { - match lvl { - Bug | Fatal | Error => { } - Warning | Note => { return; } - } - - debug!("Error: {}", msg); - match e.messages.iter().position(|m| msg.contains(m.as_slice())) { - Some(i) => { - e.messages.remove(i); - } - None => { - fail!("Unexpected error: {} Expected: {}", - msg, e.messages); - } - } -} - -impl Emitter for ExpectErrorEmitter { - fn emit(&mut self, - _cmsp: Option<(&codemap::CodeMap, Span)>, - msg: &str, - _: Option<&str>, - lvl: Level) - { - remove_message(self, msg, lvl); - } - - fn custom_emit(&mut self, - _cm: &codemap::CodeMap, - _sp: RenderSpan, - msg: &str, - lvl: Level) - { - remove_message(self, msg, lvl); - } -} - -fn errors(msgs: &[&str]) -> (Box, uint) { - let v = msgs.iter().map(|m| m.to_string()).collect(); - (box ExpectErrorEmitter { messages: v } as Box, msgs.len()) -} - -fn test_env(_test_name: &str, - source_string: &str, - (emitter, expected_err_count): (Box, uint), - body: |Env|) { - let options = - config::basic_options(); - let codemap = - CodeMap::new(); - let diagnostic_handler = - diagnostic::mk_handler(emitter); - let span_diagnostic_handler = - diagnostic::mk_span_handler(diagnostic_handler, codemap); - - let sess = session::build_session_(options, None, span_diagnostic_handler); - let krate_config = Vec::new(); - let input = driver::StrInput(source_string.to_string()); - let krate = driver::phase_1_parse_input(&sess, krate_config, &input); - let (krate, ast_map) = - driver::phase_2_configure_and_expand(&sess, krate, "test", None) - .expect("phase 2 aborted"); - - // run just enough stuff to build a tcx: - let lang_items = lang_items::collect_language_items(&krate, &sess); - let resolve::CrateMap { def_map: def_map, .. } = - resolve::resolve_crate(&sess, &lang_items, &krate); - let (freevars_map, captures_map) = freevars::annotate_freevars(&def_map, - &krate); - let named_region_map = resolve_lifetime::krate(&sess, &krate); - let region_map = region::resolve_crate(&sess, &krate); - let stability_index = stability::Index::build(&krate); - let tcx = ty::mk_ctxt(sess, - def_map, - named_region_map, - ast_map, - freevars_map, - captures_map, - region_map, - lang_items, - stability_index); - let infcx = infer::new_infer_ctxt(&tcx); - let env = Env {krate: krate, - tcx: &tcx, - infcx: &infcx}; - body(env); - infcx.resolve_regions_and_report_errors(); - assert_eq!(tcx.sess.err_count(), expected_err_count); -} - -impl<'a> Env<'a> { - pub fn create_region_hierarchy(&self, rh: &RH) { - for child_rh in rh.sub.iter() { - self.create_region_hierarchy(child_rh); - self.tcx.region_maps.record_encl_scope(child_rh.id, rh.id); - } - } - - pub fn create_simple_region_hierarchy(&self) { - // creates a region hierarchy where 1 is root, 10 and 11 are - // children of 1, etc - self.create_region_hierarchy( - &RH {id: 1, - sub: &[RH {id: 10, - sub: &[]}, - RH {id: 11, - sub: &[]}]}); - } - - pub fn lookup_item(&self, names: &[String]) -> ast::NodeId { - return match search_mod(self, &self.krate.module, 0, names) { - Some(id) => id, - None => { - fail!("no item found: `{}`", names.connect("::")); - } - }; - - fn search_mod(this: &Env, - m: &ast::Mod, - idx: uint, - names: &[String]) - -> Option { - assert!(idx < names.len()); - for item in m.items.iter() { - if item.ident.user_string(this.tcx) == names[idx] { - return search(this, &**item, idx+1, names); - } - } - return None; - } - - fn search(this: &Env, - it: &ast::Item, - idx: uint, - names: &[String]) - -> Option { - if idx == names.len() { - return Some(it.id); - } - - return match it.node { - ast::ItemStatic(..) | ast::ItemFn(..) | - ast::ItemForeignMod(..) | ast::ItemTy(..) => { - None - } - - ast::ItemEnum(..) | ast::ItemStruct(..) | - ast::ItemTrait(..) | ast::ItemImpl(..) | - ast::ItemMac(..) => { - None - } - - ast::ItemMod(ref m) => { - search_mod(this, m, idx, names) - } - }; - } - } - - pub fn make_subtype(&self, a: ty::t, b: ty::t) -> bool { - match infer::mk_subty(self.infcx, true, infer::Misc(DUMMY_SP), a, b) { - Ok(_) => true, - Err(ref e) => fail!("Encountered error: {}", - ty::type_err_to_str(self.tcx, e)) - } - } - - pub fn is_subtype(&self, a: ty::t, b: ty::t) -> bool { - match infer::can_mk_subty(self.infcx, a, b) { - Ok(_) => true, - Err(_) => false - } - } - - pub fn assert_subtype(&self, a: ty::t, b: ty::t) { - if !self.is_subtype(a, b) { - fail!("{} is not a subtype of {}, but it should be", - self.ty_to_string(a), - self.ty_to_string(b)); - } - } - - pub fn assert_not_subtype(&self, a: ty::t, b: ty::t) { - if self.is_subtype(a, b) { - fail!("{} is a subtype of {}, but it shouldn't be", - self.ty_to_string(a), - self.ty_to_string(b)); - } - } - - pub fn assert_eq(&self, a: ty::t, b: ty::t) { - self.assert_subtype(a, b); - self.assert_subtype(b, a); - } - - pub fn ty_to_string(&self, a: ty::t) -> String { - ty_to_string(self.tcx, a) - } - - pub fn t_fn(&self, - binder_id: ast::NodeId, - input_tys: &[ty::t], - output_ty: ty::t) - -> ty::t - { - ty::mk_ctor_fn(self.tcx, binder_id, input_tys, output_ty) - } - - pub fn t_int(&self) -> ty::t { - ty::mk_int() - } - - pub fn t_rptr_late_bound(&self, binder_id: ast::NodeId, id: uint) -> ty::t { - ty::mk_imm_rptr(self.tcx, ty::ReLateBound(binder_id, ty::BrAnon(id)), - self.t_int()) - } - - pub fn t_rptr_scope(&self, id: ast::NodeId) -> ty::t { - ty::mk_imm_rptr(self.tcx, ty::ReScope(id), self.t_int()) - } - - pub fn t_rptr_free(&self, nid: ast::NodeId, id: uint) -> ty::t { - ty::mk_imm_rptr(self.tcx, - ty::ReFree(ty::FreeRegion {scope_id: nid, - bound_region: ty::BrAnon(id)}), - self.t_int()) - } - - pub fn t_rptr_static(&self) -> ty::t { - ty::mk_imm_rptr(self.tcx, ty::ReStatic, self.t_int()) - } - - pub fn dummy_type_trace(&self) -> infer::TypeTrace { - infer::TypeTrace { - origin: infer::Misc(DUMMY_SP), - values: infer::Types(ty::expected_found { - expected: ty::mk_err(), - found: ty::mk_err(), - }) - } - } - - pub fn lub(&self) -> Lub<'a> { - let trace = self.dummy_type_trace(); - Lub(self.infcx.combine_fields(true, trace)) - } - - pub fn glb(&self) -> Glb<'a> { - let trace = self.dummy_type_trace(); - Glb(self.infcx.combine_fields(true, trace)) - } - - pub fn resolve_regions(&self) { - self.infcx.resolve_regions_and_report_errors(); - } - - pub fn make_lub_ty(&self, t1: ty::t, t2: ty::t) -> ty::t { - match self.lub().tys(t1, t2) { - Ok(t) => t, - Err(ref e) => fail!("unexpected error computing LUB: {:?}", - ty::type_err_to_str(self.tcx, e)) - } - } - - /// Checks that `LUB(t1,t2) == t_lub` - pub fn check_lub(&self, t1: ty::t, t2: ty::t, t_lub: ty::t) { - match self.lub().tys(t1, t2) { - Ok(t) => { - self.assert_eq(t, t_lub); - } - Err(ref e) => { - fail!("unexpected error in LUB: {}", - ty::type_err_to_str(self.tcx, e)) - } - } - } - - /// Checks that `GLB(t1,t2) == t_glb` - pub fn check_glb(&self, t1: ty::t, t2: ty::t, t_glb: ty::t) { - debug!("check_glb(t1={}, t2={}, t_glb={})", - self.ty_to_string(t1), - self.ty_to_string(t2), - self.ty_to_string(t_glb)); - match self.glb().tys(t1, t2) { - Err(e) => { - fail!("unexpected error computing LUB: {:?}", e) - } - Ok(t) => { - self.assert_eq(t, t_glb); - - // sanity check for good measure: - self.assert_subtype(t, t1); - self.assert_subtype(t, t2); - } - } - } - - /// Checks that `LUB(t1,t2)` is undefined - pub fn check_no_lub(&self, t1: ty::t, t2: ty::t) { - match self.lub().tys(t1, t2) { - Err(_) => {} - Ok(t) => { - fail!("unexpected success computing LUB: {}", self.ty_to_string(t)) - } - } - } - - /// Checks that `GLB(t1,t2)` is undefined - pub fn check_no_glb(&self, t1: ty::t, t2: ty::t) { - match self.glb().tys(t1, t2) { - Err(_) => {} - Ok(t) => { - fail!("unexpected success computing GLB: {}", self.ty_to_string(t)) - } - } - } -} - -#[test] -fn contravariant_region_ptr_ok() { - test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| { - env.create_simple_region_hierarchy(); - let t_rptr1 = env.t_rptr_scope(1); - let t_rptr10 = env.t_rptr_scope(10); - env.assert_eq(t_rptr1, t_rptr1); - env.assert_eq(t_rptr10, t_rptr10); - env.make_subtype(t_rptr1, t_rptr10); - }) -} - -#[test] -fn contravariant_region_ptr_err() { - test_env("contravariant_region_ptr", - EMPTY_SOURCE_STR, - errors(["lifetime mismatch"]), - |env| { - env.create_simple_region_hierarchy(); - let t_rptr1 = env.t_rptr_scope(1); - let t_rptr10 = env.t_rptr_scope(10); - env.assert_eq(t_rptr1, t_rptr1); - env.assert_eq(t_rptr10, t_rptr10); - - // will cause an error when regions are resolved - env.make_subtype(t_rptr10, t_rptr1); - }) -} - -#[test] -fn lub_bound_bound() { - test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| { - let t_rptr_bound1 = env.t_rptr_late_bound(22, 1); - let t_rptr_bound2 = env.t_rptr_late_bound(22, 2); - env.check_lub(env.t_fn(22, [t_rptr_bound1], env.t_int()), - env.t_fn(22, [t_rptr_bound2], env.t_int()), - env.t_fn(22, [t_rptr_bound1], env.t_int())); - }) -} - -#[test] -fn lub_bound_free() { - test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| { - let t_rptr_bound1 = env.t_rptr_late_bound(22, 1); - let t_rptr_free1 = env.t_rptr_free(0, 1); - env.check_lub(env.t_fn(22, [t_rptr_bound1], env.t_int()), - env.t_fn(22, [t_rptr_free1], env.t_int()), - env.t_fn(22, [t_rptr_free1], env.t_int())); - }) -} - -#[test] -fn lub_bound_static() { - test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| { - let t_rptr_bound1 = env.t_rptr_late_bound(22, 1); - let t_rptr_static = env.t_rptr_static(); - env.check_lub(env.t_fn(22, [t_rptr_bound1], env.t_int()), - env.t_fn(22, [t_rptr_static], env.t_int()), - env.t_fn(22, [t_rptr_static], env.t_int())); - }) -} - -#[test] -fn lub_bound_bound_inverse_order() { - test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| { - let t_rptr_bound1 = env.t_rptr_late_bound(22, 1); - let t_rptr_bound2 = env.t_rptr_late_bound(22, 2); - env.check_lub(env.t_fn(22, [t_rptr_bound1, t_rptr_bound2], t_rptr_bound1), - env.t_fn(22, [t_rptr_bound2, t_rptr_bound1], t_rptr_bound1), - env.t_fn(22, [t_rptr_bound1, t_rptr_bound1], t_rptr_bound1)); - }) -} - -#[test] -fn lub_free_free() { - test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| { - let t_rptr_free1 = env.t_rptr_free(0, 1); - let t_rptr_free2 = env.t_rptr_free(0, 2); - let t_rptr_static = env.t_rptr_static(); - env.check_lub(env.t_fn(22, [t_rptr_free1], env.t_int()), - env.t_fn(22, [t_rptr_free2], env.t_int()), - env.t_fn(22, [t_rptr_static], env.t_int())); - }) -} - -#[test] -fn lub_returning_scope() { - test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, - errors(["cannot infer an appropriate lifetime"]), |env| { - let t_rptr_scope10 = env.t_rptr_scope(10); - let t_rptr_scope11 = env.t_rptr_scope(11); - - // this should generate an error when regions are resolved - env.make_lub_ty(env.t_fn(22, [], t_rptr_scope10), - env.t_fn(22, [], t_rptr_scope11)); - }) -} - -#[test] -fn glb_free_free_with_common_scope() { - test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| { - let t_rptr_free1 = env.t_rptr_free(0, 1); - let t_rptr_free2 = env.t_rptr_free(0, 2); - let t_rptr_scope = env.t_rptr_scope(0); - env.check_glb(env.t_fn(22, [t_rptr_free1], env.t_int()), - env.t_fn(22, [t_rptr_free2], env.t_int()), - env.t_fn(22, [t_rptr_scope], env.t_int())); - }) -} - -#[test] -fn glb_bound_bound() { - test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| { - let t_rptr_bound1 = env.t_rptr_late_bound(22, 1); - let t_rptr_bound2 = env.t_rptr_late_bound(22, 2); - env.check_glb(env.t_fn(22, [t_rptr_bound1], env.t_int()), - env.t_fn(22, [t_rptr_bound2], env.t_int()), - env.t_fn(22, [t_rptr_bound1], env.t_int())); - }) -} - -#[test] -fn glb_bound_free() { - test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| { - let t_rptr_bound1 = env.t_rptr_late_bound(22, 1); - let t_rptr_free1 = env.t_rptr_free(0, 1); - env.check_glb(env.t_fn(22, [t_rptr_bound1], env.t_int()), - env.t_fn(22, [t_rptr_free1], env.t_int()), - env.t_fn(22, [t_rptr_bound1], env.t_int())); - }) -} - -#[test] -fn glb_bound_static() { - test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| { - let t_rptr_bound1 = env.t_rptr_late_bound(22, 1); - let t_rptr_static = env.t_rptr_static(); - env.check_glb(env.t_fn(22, [t_rptr_bound1], env.t_int()), - env.t_fn(22, [t_rptr_static], env.t_int()), - env.t_fn(22, [t_rptr_bound1], env.t_int())); - }) -} diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 4000807ec1b8e..77300faad57b3 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -354,7 +354,6 @@ pub fn require_same_types(tcx: &ty::ctxt, msg(), ty::type_err_to_str(tcx, terr)).as_slice()); - ty::note_and_explain_type_err(tcx, terr); false } } diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs index 530f65855d42c..f384f818c1813 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc/middle/typeck/rscope.rs @@ -59,22 +59,21 @@ pub struct SpecificRscope { } impl SpecificRscope { - pub fn new(r: ty::Region) -> SpecificRscope { - SpecificRscope { default: r } + pub fn new(r: &ty::Region) -> SpecificRscope { + SpecificRscope { + default: (*r).clone() + } } } impl RegionScope for SpecificRscope { fn default_region_bound(&self, _span: Span) -> Option { - Some(self.default) + Some(self.default.clone()) } - fn anon_regions(&self, - _span: Span, - count: uint) - -> Result , ()> - { - Ok(Vec::from_elem(count, self.default)) + fn anon_regions(&self, _span: Span, count: uint) + -> Result, ()> { + Ok(Vec::from_elem(count, self.default.clone())) } } @@ -101,16 +100,12 @@ impl BindingRscope { } impl RegionScope for BindingRscope { - fn default_region_bound(&self, _span: Span) -> Option - { + fn default_region_bound(&self, _span: Span) -> Option { Some(self.next_region()) } - fn anon_regions(&self, - _: Span, - count: uint) - -> Result , ()> - { + fn anon_regions(&self, _: Span, count: uint) + -> Result, ()> { Ok(Vec::from_fn(count, |_| self.next_region())) } } diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index e6227b9c12829..16e8618af02a5 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -730,12 +730,12 @@ impl<'a> ConstraintContext<'a> { /* leaf type -- noop */ } - ty::ty_unboxed_closure(_, region) => { + ty::ty_unboxed_closure(_, ref region) => { let contra = self.contravariant(variance); self.add_constraints_from_region(region, contra); } - ty::ty_rptr(region, ref mt) => { + ty::ty_rptr(ref region, ref mt) => { let contra = self.contravariant(variance); self.add_constraints_from_region(region, contra); self.add_constraints_from_mt(mt, variance); @@ -824,8 +824,11 @@ impl<'a> ConstraintContext<'a> { self.add_constraints_from_sig(sig, variance); } - ty::ty_closure(box ty::ClosureTy { ref sig, - store: ty::RegionTraitStore(region, _), .. }) => { + ty::ty_closure(box ty::ClosureTy { + ref sig, + store: ty::RegionTraitStore(ref region, _), + .. + }) => { let contra = self.contravariant(variance); self.add_constraints_from_region(region, contra); self.add_constraints_from_sig(sig, variance); @@ -865,7 +868,7 @@ impl<'a> ConstraintContext<'a> { self.declared_variance(p.def_id, def_id, RegionParam, p.space, p.index); let variance_i = self.xform(variance, variance_decl); - let substs_r = *substs.regions().get(p.space, p.index); + let substs_r = substs.regions().get(p.space, p.index); self.add_constraints_from_region(substs_r, variance_i); } } @@ -885,9 +888,9 @@ impl<'a> ConstraintContext<'a> { /// Adds constraints appropriate for a region appearing in a /// context with ambient variance `variance` fn add_constraints_from_region(&mut self, - region: ty::Region, + region: &ty::Region, variance: VarianceTermPtr<'a>) { - match region { + match *region { ty::ReEarlyBound(param_id, _, _, _) => { if self.is_to_be_inferred(param_id) { let index = self.inferred_index(param_id); @@ -902,7 +905,7 @@ impl<'a> ConstraintContext<'a> { // methods or in fn types. } - ty::ReFree(..) | ty::ReScope(..) | ty::ReInfer(..) | + ty::ReFree(..) | ty::ReSemeRegion(..) | ty::ReInfer(..) | ty::ReEmpty => { // We don't expect to see anything but 'static or bound // regions when visiting member types or method types. diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 11f16f1ea9511..7ee1555484a2b 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -14,7 +14,7 @@ use middle::subst::{VecPerParamSpace,Subst}; use middle::subst; use middle::ty::{BoundRegion, BrAnon, BrNamed}; use middle::ty::{ReEarlyBound, BrFresh, ctxt}; -use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, ReEmpty}; +use middle::ty::{ReFree, ReSemeRegion, ReInfer, ReStatic, Region, ReEmpty}; use middle::ty::{ReSkolemized, ReVar}; use middle::ty::{mt, t, ParamTy}; use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum}; @@ -49,7 +49,7 @@ pub trait UserString { pub fn note_and_explain_region(cx: &ctxt, prefix: &str, - region: ty::Region, + region: &ty::Region, suffix: &str) { match explain_region_and_span(cx, region) { (ref str, Some(span)) => { @@ -80,34 +80,44 @@ fn item_scope_tag(item: &ast::Item) -> &'static str { } } -pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) - -> (String, Option) { - return match region { - ReScope(node_id) => { +pub fn explain_region_and_span(cx: &ctxt, region: &ty::Region) + -> (String, Option) { + return match *region { + ReSemeRegion(ref seme_region) => { + let node_id = seme_region.lub_scope(cx); match cx.map.find(node_id) { Some(ast_map::NodeBlock(ref blk)) => { explain_span(cx, "block", blk.span) } Some(ast_map::NodeExpr(expr)) => { match expr.node { - ast::ExprCall(..) => explain_span(cx, "call", expr.span), + ast::ExprCall(..) => { + explain_span(cx, "call", expr.span) + } ast::ExprMethodCall(..) => { explain_span(cx, "method call", expr.span) }, - ast::ExprMatch(..) => explain_span(cx, "match", expr.span), + ast::ExprMatch(..) => { + explain_span(cx, "match", expr.span) + } _ => explain_span(cx, "expression", expr.span) } } Some(ast_map::NodeStmt(stmt)) => { explain_span(cx, "statement", stmt.span) } - Some(ast_map::NodeItem(it)) => { - let tag = item_scope_tag(&*it); - explain_span(cx, tag, it.span) + Some(ast_map::NodeArm(arm)) => { + explain_span(cx, "match arm", arm.span) + } + Some(ast_map::NodeItem(it)) if (match it.node { + ast::ItemFn(..) => true, _ => false + }) => { + explain_span(cx, "function body", it.span) } Some(_) | None => { // this really should not happen - (format!("unknown scope: {}. Please report a bug.", node_id), None) + (format!("unknown scope: {}. Please report a bug.", node_id), + None) } } } @@ -189,11 +199,12 @@ pub fn bound_region_to_string(cx: &ctxt, // In general, if you are giving a region error message, // you should use `explain_region()` or, better yet, // `note_and_explain_region()` -pub fn region_ptr_to_string(cx: &ctxt, region: Region) -> String { +pub fn region_ptr_to_string(cx: &ctxt, region: &Region) -> String { region_to_string(cx, "&", true, region) } -pub fn region_to_string(cx: &ctxt, prefix: &str, space: bool, region: Region) -> String { +pub fn region_to_string(cx: &ctxt, prefix: &str, space: bool, region: &Region) + -> String { let space_str = if space { " " } else { "" }; if cx.sess.verbose() { @@ -204,8 +215,8 @@ pub fn region_to_string(cx: &ctxt, prefix: &str, space: bool, region: Region) -> // the user might want to diagnose an error, but there is basically no way // to fit that into a short string. Hence the recommendation to use // `explain_region()` or `note_and_explain_region()`. - match region { - ty::ReScope(_) => prefix.to_string(), + match *region { + ty::ReSemeRegion(..) => prefix.to_string(), ty::ReEarlyBound(_, _, _, name) => { token::get_name(name).get().to_string() } @@ -231,11 +242,13 @@ pub fn mt_to_string(cx: &ctxt, m: &mt) -> String { format!("{}{}", mutability_to_string(m.mutbl), ty_to_string(cx, m.ty)) } -pub fn trait_store_to_string(cx: &ctxt, s: ty::TraitStore) -> String { - match s { +pub fn trait_store_to_string(cx: &ctxt, s: &ty::TraitStore) -> String { + match *s { ty::UniqTraitStore => "Box ".to_string(), - ty::RegionTraitStore(r, m) => { - format!("{}{}", region_ptr_to_string(cx, r), mutability_to_string(m)) + ty::RegionTraitStore(ref r, m) => { + format!("{}{}", + region_ptr_to_string(cx, r), + mutability_to_string(m)) } } } @@ -297,7 +310,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { match cty.store { ty::UniqTraitStore => {} - ty::RegionTraitStore(region, _) => { + ty::RegionTraitStore(ref region, _) => { s.push_str(region_to_string(cx, "", true, region).as_slice()); } } @@ -384,7 +397,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { ast::MutImmutable => "const", }, ty_to_string(cx, tm.ty)) } - ty_rptr(r, ref tm) => { + ty_rptr(ref r, ref tm) => { let mut buf = region_ptr_to_string(cx, r); buf.push_str(mt_to_string(cx, tm).as_slice()); buf @@ -461,7 +474,7 @@ pub fn parameterized(cx: &ctxt, match substs.regions { subst::ErasedRegions => { } subst::NonerasedRegions(ref regions) => { - for &r in regions.iter() { + for r in regions.iter() { let s = region_to_string(cx, "", false, r); if !s.is_empty() { strs.push(s) @@ -779,8 +792,8 @@ impl Repr for ty::Region { ty::ReFree(ref fr) => fr.repr(tcx), - ty::ReScope(id) => { - format!("ReScope({})", id) + ty::ReSemeRegion(ref seme_region) => { + format!("ReSemeRegion({})", seme_region) } ty::ReStatic => { @@ -804,7 +817,7 @@ impl Repr for ty::Region { impl UserString for ty::Region { fn user_string(&self, tcx: &ctxt) -> String { - region_to_string(tcx, "", false, *self) + region_to_string(tcx, "", false, self) } } @@ -984,7 +997,7 @@ impl Repr for typeck::MethodObject { impl Repr for ty::TraitStore { fn repr(&self, tcx: &ctxt) -> String { - trait_store_to_string(tcx, *self) + trait_store_to_string(tcx, self) } } @@ -1192,13 +1205,13 @@ impl Repr for ty::ExplicitSelfCategory { impl Repr for regionmanip::WfConstraint { fn repr(&self, tcx: &ctxt) -> String { match *self { - regionmanip::RegionSubRegionConstraint(_, r_a, r_b) => { + regionmanip::RegionSubRegionConstraint(_, ref r_a, ref r_b) => { format!("RegionSubRegionConstraint({}, {})", r_a.repr(tcx), r_b.repr(tcx)) } - regionmanip::RegionSubParamConstraint(_, r, p) => { + regionmanip::RegionSubParamConstraint(_, ref r, p) => { format!("RegionSubParamConstraint({}, {})", r.repr(tcx), p.repr(tcx)) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a630d6bb5f67a..094cd0052b163 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -644,7 +644,7 @@ impl Clean> for ty::Region { ty::ReLateBound(..) | ty::ReFree(..) | - ty::ReScope(..) | + ty::ReSemeRegion(..) | ty::ReInfer(..) | ty::ReEmpty(..) => None } @@ -996,16 +996,16 @@ impl Clean for ty::Method { let (self_, sig) = match self.explicit_self { ty::StaticExplicitSelfCategory => (ast::SelfStatic.clean(), self.fty.sig.clone()), - s => { + ref s => { let sig = ty::FnSig { inputs: Vec::from_slice(self.fty.sig.inputs.slice_from(1)), ..self.fty.sig.clone() }; - let s = match s { + let s = match *s { ty::ByValueExplicitSelfCategory => SelfValue, ty::ByReferenceExplicitSelfCategory(..) => { match ty::get(self.fty.sig.inputs[0]).sty { - ty::ty_rptr(r, mt) => { + ty::ty_rptr(ref r, mt) => { SelfBorrowed(r.clean(), mt.mutbl.clean()) } _ => unreachable!(), @@ -1259,7 +1259,7 @@ impl Clean for ty::t { ty::ty_vec(ty, Some(i)) => FixedVector(box ty.clean(), format!("{}", i)), ty::ty_ptr(mt) => RawPointer(mt.mutbl.clean(), box mt.ty.clean()), - ty::ty_rptr(r, mt) => BorrowedRef { + ty::ty_rptr(ref r, mt) => BorrowedRef { lifetime: r.clean(), mutability: mt.mutbl.clean(), type_: box mt.ty.clean(), diff --git a/src/libstd/io/mem.rs b/src/libstd/io/mem.rs index 21ab9c1fdd431..eada174fcc285 100644 --- a/src/libstd/io/mem.rs +++ b/src/libstd/io/mem.rs @@ -148,7 +148,9 @@ impl Reader for MemReader { { let input = self.buf.slice(self.pos, self.pos + write_len); let output = buf.mut_slice(0, write_len); - assert_eq!(input.len(), output.len()); + let input_len = input.len(); + let output_len = output.len(); + assert_eq!(input_len, output_len); slice::bytes::copy_memory(output, input); } self.pos += write_len; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 68a1c521f1942..1151bfecd90da 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -481,6 +481,8 @@ pub struct Arm { pub pats: Vec>, pub guard: Option>, pub body: Gc, + pub id: NodeId, + pub span: Span, } #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] @@ -531,7 +533,7 @@ pub enum Expr_ { // Conditionless loop (can be exited with break, cont, or ret) // FIXME #6993: change to Option ... or not, if these are hygienic. ExprLoop(P, Option), - ExprMatch(Gc, Vec), + ExprMatch(Gc, Vec>), ExprFnBlock(CaptureClause, P, P), ExprProc(P, P), ExprUnboxedFn(CaptureClause, UnboxedClosureKind, P, P), @@ -556,7 +558,7 @@ pub enum Expr_ { ExprMac(Mac), /// A struct literal expression. - ExprStruct(Path, Vec , Option> /* base */), + ExprStruct(Path, Vec, Option> /* base */), /// A vector literal constructed from one repeated element. ExprRepeat(Gc /* element */, Gc /* count */), diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index d1f78c71e19df..b7aaf4c6cbe20 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -107,6 +107,7 @@ pub enum Node { NodeArg(Gc), NodeLocal(Gc), NodePat(Gc), + NodeArm(Gc), NodeBlock(P), /// NodeStructCtor represents a tuple struct. @@ -133,6 +134,7 @@ enum MapEntry { EntryArg(NodeId, Gc), EntryLocal(NodeId, Gc), EntryPat(NodeId, Gc), + EntryArm(NodeId, Gc), EntryBlock(NodeId, P), EntryStructCtor(NodeId, Gc), EntryLifetime(NodeId, Gc), @@ -161,6 +163,7 @@ impl MapEntry { EntryArg(id, _) => id, EntryLocal(id, _) => id, EntryPat(id, _) => id, + EntryArm(id, _) => id, EntryBlock(id, _) => id, EntryStructCtor(id, _) => id, EntryLifetime(id, _) => id, @@ -180,6 +183,7 @@ impl MapEntry { EntryArg(_, p) => NodeArg(p), EntryLocal(_, p) => NodeLocal(p), EntryPat(_, p) => NodePat(p), + EntryArm(_, p) => NodeArm(p), EntryBlock(_, p) => NodeBlock(p), EntryStructCtor(_, p) => NodeStructCtor(p), EntryLifetime(_, p) => NodeLifetime(p), @@ -461,6 +465,7 @@ impl Map { Some(NodeStmt(stmt)) => stmt.span, Some(NodeArg(pat)) | Some(NodeLocal(pat)) => pat.span, Some(NodePat(pat)) => pat.span, + Some(NodeArm(arm)) => arm.span, Some(NodeBlock(block)) => block.span, Some(NodeStructCtor(_)) => self.expect_item(self.get_parent(id)).span, _ => return None, @@ -714,6 +719,12 @@ impl<'a, F: FoldOps> Folder for Ctx<'a, F> { pat } + fn fold_arm(&mut self, arm: Gc) -> Gc { + let arm = fold::noop_fold_arm(arm, self); + self.insert(arm.id, EntryArm(self.parent, arm)); + arm + } + fn fold_expr(&mut self, expr: Gc) -> Gc { let expr = fold::noop_fold_expr(expr, self); @@ -870,6 +881,7 @@ impl<'a> NodePrinter for pprust::State<'a> { NodeExpr(a) => self.print_expr(&*a), NodeStmt(a) => self.print_stmt(&*a), NodePat(a) => self.print_pat(&*a), + NodeArm(a) => self.print_arm(&*a), NodeBlock(a) => self.print_block(&*a), NodeLifetime(a) => self.print_lifetime(&*a), @@ -946,6 +958,9 @@ fn node_id_to_string(map: &Map, id: NodeId) -> String { Some(NodePat(ref pat)) => { format!("pat {} (id={})", pprust::pat_to_string(&**pat), id) } + Some(NodeArm(ref arm)) => { + format!("arm {} (id={})", pprust::arm_to_string(&**arm), id) + } Some(NodeBlock(ref block)) => { format!("block {} (id={})", pprust::block_to_string(&**block), id) } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 64ab0e5cb191f..9928077ba4bce 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -31,9 +31,9 @@ mod syntax { pub trait AstBuilder { // paths - fn path(&self, span: Span, strs: Vec ) -> ast::Path; + fn path(&self, span: Span, strs: Vec) -> ast::Path; fn path_ident(&self, span: Span, id: ast::Ident) -> ast::Path; - fn path_global(&self, span: Span, strs: Vec ) -> ast::Path; + fn path_global(&self, span: Span, strs: Vec) -> ast::Path; fn path_all(&self, sp: Span, global: bool, idents: Vec , @@ -184,10 +184,15 @@ pub trait AstBuilder { fn pat_ok(&self, span: Span, pat: Gc) -> Gc; fn pat_err(&self, span: Span, pat: Gc) -> Gc; - fn arm(&self, span: Span, pats: Vec> , expr: Gc) -> ast::Arm; - fn arm_unreachable(&self, span: Span) -> ast::Arm; + fn arm(&self, span: Span, pats: Vec>, expr: Gc) + -> Gc; + fn arm_unreachable(&self, span: Span) -> Gc; - fn expr_match(&self, span: Span, arg: Gc, arms: Vec ) -> Gc; + fn expr_match(&self, + span: Span, + arg: Gc, + arms: Vec>) + -> Gc; fn expr_if(&self, span: Span, cond: Gc, then: Gc, els: Option>) -> Gc; @@ -847,21 +852,27 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.pat_enum(span, path, vec!(pat)) } - fn arm(&self, _span: Span, pats: Vec> , expr: Gc) -> ast::Arm { - ast::Arm { + fn arm(&self, span: Span, pats: Vec> , expr: Gc) + -> Gc { + box(GC) ast::Arm { attrs: vec!(), pats: pats, guard: None, - body: expr + body: expr, + id: ast::DUMMY_NODE_ID, + span: span, } } - fn arm_unreachable(&self, span: Span) -> ast::Arm { + fn arm_unreachable(&self, span: Span) -> Gc { self.arm(span, vec!(self.pat_wild(span)), self.expr_unreachable(span)) } - fn expr_match(&self, span: Span, arg: Gc, - arms: Vec) -> Gc { + fn expr_match(&self, + span: Span, + arg: Gc, + arms: Vec>) + -> Gc { self.expr(span, ast::ExprMatch(arg, arms)) } diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 50bdc296aad76..c5ebd93bb5fc5 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -914,7 +914,7 @@ impl<'a> MethodDef<'a> { // (Variant2, Variant2, ...) => Body2 // ... // where each tuple has length = self_args.len() - let mut match_arms : Vec = variants.iter().enumerate() + let mut match_arms : Vec> = variants.iter().enumerate() .map(|(index, &variant)| { // These self_pats have form Variant1, Variant2, ... @@ -1012,7 +1012,7 @@ impl<'a> MethodDef<'a> { // unreachable-pattern error. // if variants.len() > 1 && self_args.len() > 1 { - let arms : Vec = variants.iter().enumerate() + let arms: Vec> = variants.iter().enumerate() .map(|(index, &variant)| { let pat = variant_to_pat(cx, sp, &*variant); let lit = ast::LitInt(index as u64, ast::UnsignedIntLit(ast::TyU)); diff --git a/src/libsyntax/ext/deriving/primitive.rs b/src/libsyntax/ext/deriving/primitive.rs index 30dd8e9683ad5..0a7d3bb194f57 100644 --- a/src/libsyntax/ext/deriving/primitive.rs +++ b/src/libsyntax/ext/deriving/primitive.rs @@ -17,7 +17,7 @@ use ext::deriving::generic::*; use ext::deriving::generic::ty::*; use parse::token::InternedString; -use std::gc::Gc; +use std::gc::{Gc, GC}; pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt, span: Span, @@ -113,11 +113,13 @@ fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, let body = cx.expr_some(span, variant); // arm for `_ if $guard => $body` - let arm = ast::Arm { + let arm = box(GC) ast::Arm { attrs: vec!(), pats: vec!(cx.pat_wild(span)), guard: Some(guard), body: body, + id: ast::DUMMY_NODE_ID, + span: span, }; arms.push(arm); @@ -133,11 +135,13 @@ fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, } // arm for `_ => None` - let arm = ast::Arm { + let arm = box(GC) ast::Arm { attrs: vec!(), pats: vec!(cx.pat_wild(trait_span)), guard: None, body: cx.expr_none(trait_span), + id: ast::DUMMY_NODE_ID, + span: trait_span, }; arms.push(arm); diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index c652b5a5bed9a..deddbfc1ea788 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -119,7 +119,7 @@ fn rand_substructure(cx: &mut ExtCtxt, trait_span: Span, let thing = rand_thing(cx, v_span, ident, summary, |cx, sp| rand_call(cx, sp)); cx.arm(v_span, vec!( pat ), thing) - }).collect:: >(); + }).collect::>>(); // _ => {} at the end. Should never occur arms.push(cx.arm_unreachable(trait_span)); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index d0f3cf6f9d7ad..62d4103182b30 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -614,7 +614,7 @@ fn expand_non_macro_stmt(s: &Stmt, fld: &mut MacroExpander) } // expand the arm of a 'match', renaming for macro hygiene -fn expand_arm(arm: &ast::Arm, fld: &mut MacroExpander) -> ast::Arm { +fn expand_arm(arm: &ast::Arm, fld: &mut MacroExpander) -> Gc { // expand pats... they might contain macro uses: let expanded_pats : Vec> = arm.pats.iter().map(|pat| fld.fold_pat(*pat)).collect(); if expanded_pats.len() == 0 { @@ -635,11 +635,13 @@ fn expand_arm(arm: &ast::Arm, fld: &mut MacroExpander) -> ast::Arm { let rewritten_guard = arm.guard.map(|g| fld.fold_expr(rename_fld.fold_expr(g))); let rewritten_body = fld.fold_expr(rename_fld.fold_expr(arm.body)); - ast::Arm { + box(GC) ast::Arm { attrs: arm.attrs.iter().map(|x| fld.fold_attribute(*x)).collect(), pats: rewritten_pats, guard: rewritten_guard, body: rewritten_body, + id: fld.new_id(arm.id), + span: fld.new_span(arm.span), } } @@ -949,8 +951,8 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> { expand_block(&*block, self) } - fn fold_arm(&mut self, arm: &ast::Arm) -> ast::Arm { - expand_arm(arm, self) + fn fold_arm(&mut self, arm: Gc) -> Gc { + expand_arm(&*arm, self) } fn fold_method(&mut self, method: Gc) -> SmallVector> { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 7deabed04b824..467b6b98e7aa8 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -98,7 +98,7 @@ pub trait Folder { noop_fold_stmt(s, self) } - fn fold_arm(&mut self, a: &Arm) -> Arm { + fn fold_arm(&mut self, a: Gc) -> Gc { noop_fold_arm(a, self) } @@ -318,12 +318,14 @@ pub fn noop_fold_view_path(view_path: Gc, fld: &mut T) -> G } } -pub fn noop_fold_arm(a: &Arm, fld: &mut T) -> Arm { - Arm { +pub fn noop_fold_arm(a: Gc, fld: &mut T) -> Gc { + box(GC) Arm { attrs: a.attrs.iter().map(|x| fld.fold_attribute(*x)).collect(), pats: a.pats.iter().map(|x| fld.fold_pat(*x)).collect(), guard: a.guard.map(|x| fld.fold_expr(x)), body: fld.fold_expr(a.body), + id: fld.new_id(a.id), + span: fld.new_span(a.span), } } @@ -1149,7 +1151,7 @@ pub fn noop_fold_expr(e: Gc, folder: &mut T) -> Gc { } ExprMatch(expr, ref arms) => { ExprMatch(folder.fold_expr(expr), - arms.iter().map(|x| folder.fold_arm(x)).collect()) + arms.iter().map(|x| folder.fold_arm(*x)).collect()) } ExprFnBlock(capture_clause, ref decl, ref body) => { ExprFnBlock(capture_clause, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 545bf85b582f4..515b2ee047707 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2777,7 +2777,7 @@ impl<'a> Parser<'a> { let lo = self.last_span.lo; let discriminant = self.parse_expr_res(RESTRICT_NO_STRUCT_LITERAL); self.commit_expr_expecting(discriminant, token::LBRACE); - let mut arms: Vec = Vec::new(); + let mut arms: Vec> = Vec::new(); while self.token != token::RBRACE { arms.push(self.parse_arm()); } @@ -2786,7 +2786,8 @@ impl<'a> Parser<'a> { return self.mk_expr(lo, hi, ExprMatch(discriminant, arms)); } - pub fn parse_arm(&mut self) -> Arm { + pub fn parse_arm(&mut self) -> Gc { + let lo = self.span.lo; let attrs = self.parse_outer_attributes(); let pats = self.parse_pats(); let mut guard = None; @@ -2806,11 +2807,15 @@ impl<'a> Parser<'a> { self.eat(&token::COMMA); } - ast::Arm { + let hi = self.span.hi; + + box(GC) ast::Arm { attrs: attrs, pats: pats, guard: guard, body: expr, + id: ast::DUMMY_NODE_ID, + span: mk_sp(lo, hi), } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index d5bc1bfe956fb..d245f23d5d7d0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1480,7 +1480,7 @@ impl<'a> State<'a> { try!(space(&mut self.s)); try!(self.bopen()); for arm in arms.iter() { - try!(self.print_arm(arm)); + try!(self.print_arm(&**arm)); } try!(self.bclose_(expr.span, indent_unit)); } @@ -1931,7 +1931,7 @@ impl<'a> State<'a> { self.ann.post(self, NodePat(pat)) } - fn print_arm(&mut self, arm: &ast::Arm) -> IoResult<()> { + pub fn print_arm(&mut self, arm: &ast::Arm) -> IoResult<()> { // I have no idea why this check is necessary, but here it // is :( if arm.attrs.is_empty() { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 65e192e8437f3..c11eb98dc3022 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -788,7 +788,7 @@ pub fn walk_expr>(visitor: &mut V, expression: &Expr, en ExprMatch(ref subexpression, ref arms) => { visitor.visit_expr(&**subexpression, env.clone()); for arm in arms.iter() { - visitor.visit_arm(arm, env.clone()) + visitor.visit_arm(&**arm, env.clone()) } } ExprFnBlock(_, ref function_declaration, ref body) => { diff --git a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot index 4c6383324e5f9..fb6955f9a2572 100644 --- a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot @@ -15,8 +15,9 @@ digraph block { N13[label="expr x"]; N14[label="expr y"]; N15[label="expr x + y"]; - N16[label="stmt match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y, };"]; - N17[label="block { match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y, }; }"]; + N16[label="arm [x, y, ..] => x + y,"]; + N17[label="stmt match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y, };"]; + N18[label="block { match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y, }; }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -30,8 +31,9 @@ digraph block { N12 -> N13; N13 -> N14; N14 -> N15; - N15 -> N7; - N7 -> N16; - N16 -> N17; - N17 -> N1; + N15 -> N16; + N16 -> N7; + N7 -> N17; + N17 -> N18; + N18 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot index aa43ef515343a..fa102baaf590d 100644 --- a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot @@ -15,15 +15,17 @@ digraph block { N13[label="expr 1"]; N14[label="expr _y"]; N15[label="expr _y = 1"]; - N16[label="(dummy_node)"]; - N17[label="local v"]; - N18[label="pat E13b(v)"]; - N19[label="expr v"]; - N20[label="expr 1"]; - N21[label="expr v + 1"]; - N22[label="expr _y"]; - N23[label="expr _y = v + 1"]; - N24[label="block {\l let x = E13b(13);\l let _y;\l match x { E13a => _y = 1, E13b(v) => _y = v + 1, }\l}\l"]; + N16[label="arm E13a => _y = 1,"]; + N17[label="(dummy_node)"]; + N18[label="local v"]; + N19[label="pat E13b(v)"]; + N20[label="expr v"]; + N21[label="expr 1"]; + N22[label="expr v + 1"]; + N23[label="expr _y"]; + N24[label="expr _y = v + 1"]; + N25[label="arm E13b(v) => _y = v + 1,"]; + N26[label="block {\l let x = E13b(13);\l let _y;\l match x { E13a => _y = 1, E13b(v) => _y = v + 1, }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -37,16 +39,18 @@ digraph block { N12 -> N13; N13 -> N14; N14 -> N15; - N15 -> N10; - N11 -> N16; - N16 -> N17; + N15 -> N16; + N16 -> N10; + N11 -> N17; N17 -> N18; N18 -> N19; N19 -> N20; N20 -> N21; N21 -> N22; N22 -> N23; - N23 -> N10; - N10 -> N24; - N24 -> N1; + N23 -> N24; + N24 -> N25; + N25 -> N10; + N10 -> N26; + N26 -> N1; } diff --git a/src/test/run-pass-fulldeps/quote-tokens.rs b/src/test/run-pass-fulldeps/quote-tokens.rs index 60b8f09bb3ded..5ebe4a6c35442 100644 --- a/src/test/run-pass-fulldeps/quote-tokens.rs +++ b/src/test/run-pass-fulldeps/quote-tokens.rs @@ -26,7 +26,7 @@ fn syntax_extension(cx: &ExtCtxt) { let _b: Option> = quote_item!(cx, static foo : int = $e_toks; ); let _c: Gc = quote_pat!(cx, (x, 1 .. 4, *) ); let _d: Gc = quote_stmt!(cx, let x = $a; ); - let _d: syntax::ast::Arm = quote_arm!(cx, (ref x, ref y) = (x, y) ); + let _d: Gc = quote_arm!(cx, (ref x, ref y) = (x, y) ); let _e: Gc = quote_expr!(cx, match foo { $p_toks => 10 } ); let _f: Gc = quote_expr!(cx, ());