]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #17175 : pcwalton/rust/region-bounds-on-closures, r=huonw
authorbors <bors@rust-lang.org>
Sat, 13 Sep 2014 08:06:00 +0000 (08:06 +0000)
committerbors <bors@rust-lang.org>
Sat, 13 Sep 2014 08:06:00 +0000 (08:06 +0000)
This can break code like:

    fn call_rec(f: |uint| -> uint) -> uint {
        (|x| f(x))(call_rec(f))
    }

Change this code to use a temporary instead of violating the borrow
rules:

    fn call_rec(f: |uint| -> uint) -> uint {
        let tmp = call_rec(|x| f(x)); f(tmp)
    }

Closes #17144.

[breaking-change]

r? @huonw

1  2 
src/librustc/middle/typeck/check/regionck.rs

index 8cd8a6aa051c98268f77de3012b6421a1bb6c181,6ddb10cc8ca6fb136cc37b48d1917df1ece22091..843d6a582eac3a04df67ef3b5c2c5157efc5bad4
@@@ -150,7 -150,7 +150,7 @@@ pub fn regionck_expr(fcx: &FnCtxt, e: &
      let mut rcx = Rcx::new(fcx, e.id);
      if fcx.err_count_since_creation() == 0 {
          // regionck assumes typeck succeeded
 -        rcx.visit_expr(e, ());
 +        rcx.visit_expr(e);
          rcx.visit_region_obligations(e.id);
      }
      fcx.infcx().resolve_regions_and_report_errors();
@@@ -346,7 -346,7 +346,7 @@@ impl<'a, 'tcx> Rcx<'a, 'tcx> 
  
          let len = self.region_param_pairs.len();
          self.relate_free_regions(fn_sig.as_slice(), body.id);
 -        self.visit_block(body, ());
 +        self.visit_block(body);
          self.visit_region_obligations(body.id);
          self.region_param_pairs.truncate(len);
      }
@@@ -479,7 -479,7 +479,7 @@@ impl<'fcx, 'tcx> mc::Typer<'tcx> for Rc
      }
  }
  
 -impl<'a, 'tcx> Visitor<()> for Rcx<'a, 'tcx> {
 +impl<'a, 'tcx, 'v> Visitor<'v> for Rcx<'a, 'tcx> {
      // (..) FIXME(#3238) should use visit_pat, not visit_arm/visit_local,
      // However, right now we run into an issue whereby some free
      // regions are not properly related if they appear within the
      // hierarchy, and in particular the relationships between free
      // regions, until regionck, as described in #3238.
  
 -    fn visit_fn(&mut self, _fk: &visit::FnKind, _fd: &ast::FnDecl,
 -                b: &ast::Block, _s: Span, id: ast::NodeId, _e: ()) {
 +    fn visit_fn(&mut self, _fk: visit::FnKind<'v>, _fd: &'v ast::FnDecl,
 +                b: &'v ast::Block, _s: Span, id: ast::NodeId) {
          self.visit_fn_body(id, b)
      }
  
 -    fn visit_item(&mut self, i: &ast::Item, _: ()) { visit_item(self, i); }
 +    fn visit_item(&mut self, i: &ast::Item) { visit_item(self, i); }
  
 -    fn visit_expr(&mut self, ex: &ast::Expr, _: ()) { visit_expr(self, ex); }
 +    fn visit_expr(&mut self, ex: &ast::Expr) { visit_expr(self, ex); }
  
      //visit_pat: visit_pat, // (..) see above
  
 -    fn visit_arm(&mut self, a: &ast::Arm, _: ()) { visit_arm(self, a); }
 +    fn visit_arm(&mut self, a: &ast::Arm) { visit_arm(self, a); }
  
 -    fn visit_local(&mut self, l: &ast::Local, _: ()) { visit_local(self, l); }
 +    fn visit_local(&mut self, l: &ast::Local) { visit_local(self, l); }
  
 -    fn visit_block(&mut self, b: &ast::Block, _: ()) { visit_block(self, b); }
 +    fn visit_block(&mut self, b: &ast::Block) { visit_block(self, b); }
  }
  
  fn visit_item(_rcx: &mut Rcx, _item: &ast::Item) {
  }
  
  fn visit_block(rcx: &mut Rcx, b: &ast::Block) {
 -    visit::walk_block(rcx, b, ());
 +    visit::walk_block(rcx, b);
  }
  
  fn visit_arm(rcx: &mut Rcx, arm: &ast::Arm) {
          constrain_bindings_in_pat(&**p, rcx);
      }
  
 -    visit::walk_arm(rcx, arm, ());
 +    visit::walk_arm(rcx, arm);
  }
  
  fn visit_local(rcx: &mut Rcx, l: &ast::Local) {
      // see above
      constrain_bindings_in_pat(&*l.pat, rcx);
      link_local(rcx, l);
 -    visit::walk_local(rcx, l, ());
 +    visit::walk_local(rcx, l);
  }
  
  fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) {
@@@ -625,19 -625,19 +625,19 @@@ fn visit_expr(rcx: &mut Rcx, expr: &ast
                                 false);
              }
  
 -            visit::walk_expr(rcx, expr, ());
 +            visit::walk_expr(rcx, expr);
          }
  
          ast::ExprMethodCall(_, _, ref args) => {
              constrain_call(rcx, expr, Some(*args.get(0)),
                             args.slice_from(1), false);
  
 -            visit::walk_expr(rcx, expr, ());
 +            visit::walk_expr(rcx, expr);
          }
  
          ast::ExprAssign(ref lhs, _) => {
              adjust_borrow_kind_for_assignment_lhs(rcx, &**lhs);
 -            visit::walk_expr(rcx, expr, ());
 +            visit::walk_expr(rcx, expr);
          }
  
          ast::ExprAssignOp(_, ref lhs, ref rhs) => {
  
              adjust_borrow_kind_for_assignment_lhs(rcx, &**lhs);
  
 -            visit::walk_expr(rcx, expr, ());
 +            visit::walk_expr(rcx, expr);
          }
  
          ast::ExprIndex(ref lhs, ref rhs) |
              constrain_call(rcx, expr, Some(lhs.clone()),
                             [rhs.clone()], true);
  
 -            visit::walk_expr(rcx, expr, ());
 +            visit::walk_expr(rcx, expr);
          }
  
          ast::ExprUnary(_, ref lhs) if has_method_map => {
              // As above.
              constrain_call(rcx, expr, Some(lhs.clone()), [], true);
  
 -            visit::walk_expr(rcx, expr, ());
 +            visit::walk_expr(rcx, expr);
          }
  
          ast::ExprUnary(ast::UnBox, ref base) => {
              let base_ty = rcx.resolve_node_type(base.id);
              type_must_outlive(rcx, infer::Managed(expr.span),
                                base_ty, ty::ReStatic);
 -            visit::walk_expr(rcx, expr, ());
 +            visit::walk_expr(rcx, expr);
          }
  
          ast::ExprUnary(ast::UnDeref, ref base) => {
                  _ => {}
              }
  
 -            visit::walk_expr(rcx, expr, ());
 +            visit::walk_expr(rcx, expr);
          }
  
          ast::ExprIndex(ref vec_expr, _) => {
              let vec_type = rcx.resolve_expr_type_adjusted(&**vec_expr);
              constrain_index(rcx, expr, vec_type);
  
 -            visit::walk_expr(rcx, expr, ());
 +            visit::walk_expr(rcx, expr);
          }
  
          ast::ExprCast(ref source, _) => {
              // instance.  If so, we have to be sure that the type of
              // the source obeys the trait's region bound.
              constrain_cast(rcx, expr, &**source);
 -            visit::walk_expr(rcx, expr, ());
 +            visit::walk_expr(rcx, expr);
          }
  
          ast::ExprAddrOf(m, ref base) => {
              let ty0 = rcx.resolve_node_type(expr.id);
              type_must_outlive(rcx, infer::AddrOf(expr.span),
                                ty0, ty::ReScope(expr.id));
 -            visit::walk_expr(rcx, expr, ());
 +            visit::walk_expr(rcx, expr);
          }
  
          ast::ExprMatch(ref discr, ref arms) => {
              link_match(rcx, &**discr, arms.as_slice());
  
 -            visit::walk_expr(rcx, expr, ());
 +            visit::walk_expr(rcx, expr);
          }
  
          ast::ExprFnBlock(_, _, ref body) |
  
          ast::ExprLoop(ref body, _) => {
              let repeating_scope = rcx.set_repeating_scope(body.id);
 -            visit::walk_expr(rcx, expr, ());
 +            visit::walk_expr(rcx, expr);
              rcx.set_repeating_scope(repeating_scope);
          }
  
          ast::ExprWhile(ref cond, ref body, _) => {
              let repeating_scope = rcx.set_repeating_scope(cond.id);
 -            rcx.visit_expr(&**cond, ());
 +            rcx.visit_expr(&**cond);
  
              rcx.set_repeating_scope(body.id);
 -            rcx.visit_block(&**body, ());
 +            rcx.visit_block(&**body);
  
              rcx.set_repeating_scope(repeating_scope);
          }
                  link_pattern(rcx, mc, head_cmt, &**pat);
              }
  
 -            rcx.visit_expr(&**head, ());
 +            rcx.visit_expr(&**head);
              type_of_node_must_outlive(rcx,
                                        infer::AddrOf(expr.span),
                                        head.id,
                                        ty::ReScope(expr.id));
  
              let repeating_scope = rcx.set_repeating_scope(body.id);
 -            rcx.visit_block(&**body, ());
 +            rcx.visit_block(&**body);
              rcx.set_repeating_scope(repeating_scope);
          }
  
          _ => {
 -            visit::walk_expr(rcx, expr, ());
 +            visit::walk_expr(rcx, expr);
          }
      }
  }
@@@ -890,7 -890,7 +890,7 @@@ fn check_expr_fn_block(rcx: &mut Rcx
      }
  
      let repeating_scope = rcx.set_repeating_scope(body.id);
 -    visit::walk_expr(rcx, expr, ());
 +    visit::walk_expr(rcx, expr);
      rcx.set_repeating_scope(repeating_scope);
  
      match ty::get(function_type).sty {
@@@ -1064,6 -1064,10 +1064,10 @@@ fn constrain_callee(rcx: &mut Rcx
              };
              rcx.fcx.mk_subr(infer::InvokeClosure(callee_expr.span),
                              call_region, region);
+             let region = closure_ty.bounds.region_bound;
+             rcx.fcx.mk_subr(infer::InvokeClosure(callee_expr.span),
+                             call_region, region);
          }
          _ => {
              // this should not happen, but it does if the program is