1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 The region check is a final pass that runs over the AST after we have
14 inferred the type constraints but before we have actually finalized
15 the types. Its purpose is to embed a variety of region constraints.
16 Inserting these constraints as a separate pass is good because (1) it
17 localizes the code that has to do with region inference and (2) often
18 we cannot know what constraints are needed until the basic types have
21 ### Interaction with the borrow checker
23 In general, the job of the borrowck module (which runs later) is to
24 check that all soundness criteria are met, given a particular set of
25 regions. The job of *this* module is to anticipate the needs of the
26 borrow checker and infer regions that will satisfy its requirements.
27 It is generally true that the inference doesn't need to be sound,
28 meaning that if there is a bug and we inferred bad regions, the borrow
29 checker should catch it. This is not entirely true though; for
30 example, the borrow checker doesn't check subtyping, and it doesn't
31 check that region pointers are always live when they are used. It
32 might be worthwhile to fix this so that borrowck serves as a kind of
33 verification step -- that would add confidence in the overall
34 correctness of the compiler, at the cost of duplicating some type
37 ### Inferring the duration of borrows, automatic and otherwise
39 Whenever we introduce a borrowed pointer, for example as the result of
40 a borrow expression `let x = &data`, the lifetime of the pointer `x`
41 is always specified as a region inference variable. `regionck` has the
42 job of adding constraints such that this inference variable is as
43 narrow as possible while still accommodating all uses (that is, every
44 dereference of the resulting pointer must be within the lifetime).
48 Generally speaking, `regionck` does NOT try to ensure that the data
49 `data` will outlive the pointer `x`. That is the job of borrowck. The
50 one exception is when "re-borrowing" the contents of another borrowed
51 pointer. For example, imagine you have a borrowed pointer `b` with
52 lifetime L1 and you have an expression `&*b`. The result of this
53 expression will be another borrowed pointer with lifetime L2 (which is
54 an inference variable). The borrow checker is going to enforce the
55 constraint that L2 < L1, because otherwise you are re-borrowing data
56 for a lifetime larger than the original loan. However, without the
57 routines in this module, the region inferencer would not know of this
58 dependency and thus it might infer the lifetime of L2 to be greater
59 than L1 (issue #3148).
61 There are a number of troublesome scenarios in the tests
62 `region-dependent-*.rs`, but here is one example:
65 struct Bar { foo: Foo }
66 fn get_i(x: &'a Bar) -> &'a int {
67 let foo = &x.foo; // Lifetime L1
71 Note that this comes up either with `&` expressions, `ref`
72 bindings, and `autorefs`, which are the three ways to introduce
75 The key point here is that when you are borrowing a value that
76 is "guaranteed" by a borrowed pointer, you must link the
77 lifetime of that borrowed pointer (L1, here) to the lifetime of
78 the borrow itself (L2). What do I mean by "guaranteed" by a
79 borrowed pointer? I mean any data that is reached by first
80 dereferencing a borrowed pointer and then either traversing
81 interior offsets or owned pointers. We say that the guarantor
82 of such data it the region of the borrowed pointer that was
83 traversed. This is essentially the same as the ownership
84 relation, except that a borrowed pointer never owns its
87 ### Inferring borrow kinds for upvars
89 Whenever there is a closure expression, we need to determine how each
90 upvar is used. We do this by initially assigning each upvar an
91 immutable "borrow kind" (see `ty::BorrowKind` for details) and then
92 "escalating" the kind as needed. The borrow kind proceeds according to
93 the following lattice:
95 ty::ImmBorrow -> ty::UniqueImmBorrow -> ty::MutBorrow
97 So, for example, if we see an assignment `x = 5` to an upvar `x`, we
98 will promote its borrow kind to mutable borrow. If we see an `&mut x`
99 we'll do the same. Naturally, this applies not just to the upvar, but
100 to everything owned by `x`, so the result is the same for something
101 like `x.f = 5` and so on (presuming `x` is not a borrowed pointer to a
102 struct). These adjustments are performed in
103 `adjust_upvar_borrow_kind()` (you can trace backwards through the code
106 The fact that we are inferring borrow kinds as we go results in a
107 semi-hacky interaction with mem-categorization. In particular,
108 mem-categorization will query the current borrow kind as it
109 categorizes, and we'll return the *current* value, but this may get
110 adjusted later. Therefore, in this module, we generally ignore the
111 borrow kind (and derived mutabilities) that are returned from
112 mem-categorization, since they may be inaccurate. (Another option
113 would be to use a unification scheme, where instead of returning a
114 concrete borrow kind like `ty::ImmBorrow`, we return a
115 `ty::InferBorrow(upvar_id)` or something like that, but this would
116 then mean that all later passes would have to check for these figments
117 and report an error, and it just seems like more mess in the end.)
122 use middle::def::{DefArg, DefBinding, DefLocal, DefUpvar};
123 use middle::freevars;
124 use mc = middle::mem_categorization;
125 use middle::ty::{ReScope};
127 use middle::typeck::astconv::AstConv;
128 use middle::typeck::check::FnCtxt;
129 use middle::typeck::check::regionmanip::relate_nested_regions;
130 use middle::typeck::infer::resolve_and_force_all_but_regions;
131 use middle::typeck::infer::resolve_type;
132 use middle::typeck::infer;
133 use middle::typeck::MethodCall;
134 use middle::pat_util;
135 use util::nodemap::NodeMap;
136 use util::ppaux::{ty_to_str, region_to_str, Repr};
139 use syntax::codemap::Span;
141 use syntax::visit::Visitor;
143 use std::cell::RefCell;
146 // If mem categorization results in an error, it's because the type
147 // check failed (or will fail, when the error is uncovered and
148 // reported during writeback). In this case, we just ignore this part
149 // of the code and don't try to add any more region constraints.
150 macro_rules! ignore_err(
162 // id of innermost fn or loop
163 repeating_scope: ast::NodeId,
166 fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region {
168 * Returns the validity region of `def` -- that is, how long
174 DefLocal(node_id, _) | DefArg(node_id, _) |
175 DefBinding(node_id, _) => {
176 tcx.region_maps.var_region(node_id)
178 DefUpvar(_, subdef, closure_id, body_id) => {
179 match ty::ty_closure_store(fcx.node_ty(closure_id)) {
180 ty::RegionTraitStore(..) => region_of_def(fcx, *subdef),
181 ty::UniqTraitStore => ReScope(body_id)
185 tcx.sess.bug(format!("unexpected def in region_of_def: {:?}",
192 pub fn tcx(&self) -> &'a ty::ctxt {
196 pub fn set_repeating_scope(&mut self, scope: ast::NodeId) -> ast::NodeId {
197 let old_scope = self.repeating_scope;
198 self.repeating_scope = scope;
202 pub fn resolve_type(&self, unresolved_ty: ty::t) -> ty::t {
204 * Try to resolve the type for the given node, returning
205 * t_err if an error results. Note that we never care
206 * about the details of the error, the same error will be
207 * detected and reported in the writeback phase.
209 * Note one important point: we do not attempt to resolve
210 * *region variables* here. This is because regionck is
211 * essentially adding constraints to those region variables
212 * and so may yet influence how they are resolved.
214 * Consider this silly example:
216 * fn borrow(x: &int) -> &int {x}
217 * fn foo(x: @int) -> int { // block: B
218 * let b = borrow(x); // region: <R0>
222 * Here, the region of `b` will be `<R0>`. `<R0>` is
223 * constrainted to be some subregion of the block B and some
224 * superregion of the call. If we forced it now, we'd choose
225 * the smaller region (the call). But that would make the *b
226 * illegal. Since we don't resolve, the type of b will be
227 * `&<R0>.int` and then `*b` will require that `<R0>` be
228 * bigger than the let and the `*b` expression, so we will
229 * effectively resolve `<R0>` to be the block B.
231 match resolve_type(self.fcx.infcx(), unresolved_ty,
232 resolve_and_force_all_but_regions) {
234 Err(_) => ty::mk_err()
238 /// Try to resolve the type for the given node.
239 fn resolve_node_type(&self, id: ast::NodeId) -> ty::t {
240 let t = self.fcx.node_ty(id);
244 fn resolve_method_type(&self, method_call: MethodCall) -> Option<ty::t> {
245 let method_ty = self.fcx.inh.method_map.borrow()
246 .find(&method_call).map(|method| method.ty);
247 method_ty.map(|method_ty| self.resolve_type(method_ty))
250 /// Try to resolve the type for the given node.
251 pub fn resolve_expr_type_adjusted(&mut self, expr: &ast::Expr) -> ty::t {
252 let ty_unadjusted = self.resolve_node_type(expr.id);
253 if ty::type_is_error(ty_unadjusted) || ty::type_is_bot(ty_unadjusted) {
256 let tcx = self.fcx.tcx();
257 ty::adjust_ty(tcx, expr.span, expr.id, ty_unadjusted,
258 self.fcx.inh.adjustments.borrow().find(&expr.id),
259 |method_call| self.resolve_method_type(method_call))
264 impl<'fcx> mc::Typer for Rcx<'fcx> {
265 fn tcx<'a>(&'a self) -> &'a ty::ctxt {
269 fn node_ty(&self, id: ast::NodeId) -> mc::McResult<ty::t> {
270 let t = self.resolve_node_type(id);
271 if ty::type_is_error(t) {Err(())} else {Ok(t)}
274 fn node_method_ty(&self, method_call: MethodCall) -> Option<ty::t> {
275 self.resolve_method_type(method_call)
278 fn adjustments<'a>(&'a self) -> &'a RefCell<NodeMap<ty::AutoAdjustment>> {
279 &self.fcx.inh.adjustments
282 fn is_method_call(&self, id: ast::NodeId) -> bool {
283 self.fcx.inh.method_map.borrow().contains_key(&MethodCall::expr(id))
286 fn temporary_scope(&self, id: ast::NodeId) -> Option<ast::NodeId> {
287 self.tcx().region_maps.temporary_scope(id)
290 fn upvar_borrow(&self, id: ty::UpvarId) -> ty::UpvarBorrow {
291 self.fcx.inh.upvar_borrow_map.borrow().get_copy(&id)
295 pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) {
296 let mut rcx = Rcx { fcx: fcx, repeating_scope: e.id };
298 if fcx.err_count_since_creation() == 0 {
299 // regionck assumes typeck succeeded
300 rcx.visit_expr(e, ());
302 fcx.infcx().resolve_regions_and_report_errors();
305 pub fn regionck_fn(fcx: &FnCtxt, blk: &ast::Block) {
306 let mut rcx = Rcx { fcx: fcx, repeating_scope: blk.id };
308 if fcx.err_count_since_creation() == 0 {
309 // regionck assumes typeck succeeded
310 rcx.visit_block(blk, ());
312 fcx.infcx().resolve_regions_and_report_errors();
315 impl<'a> Visitor<()> for Rcx<'a> {
316 // (..) FIXME(#3238) should use visit_pat, not visit_arm/visit_local,
317 // However, right now we run into an issue whereby some free
318 // regions are not properly related if they appear within the
319 // types of arguments that must be inferred. This could be
320 // addressed by deferring the construction of the region
321 // hierarchy, and in particular the relationships between free
322 // regions, until regionck, as described in #3238.
324 fn visit_item(&mut self, i: &ast::Item, _: ()) { visit_item(self, i); }
326 fn visit_expr(&mut self, ex: &ast::Expr, _: ()) { visit_expr(self, ex); }
328 //visit_pat: visit_pat, // (..) see above
330 fn visit_arm(&mut self, a: &ast::Arm, _: ()) { visit_arm(self, a); }
332 fn visit_local(&mut self, l: &ast::Local, _: ()) { visit_local(self, l); }
334 fn visit_block(&mut self, b: &ast::Block, _: ()) { visit_block(self, b); }
337 fn visit_item(_rcx: &mut Rcx, _item: &ast::Item) {
341 fn visit_block(rcx: &mut Rcx, b: &ast::Block) {
342 visit::walk_block(rcx, b, ());
345 fn visit_arm(rcx: &mut Rcx, arm: &ast::Arm) {
347 for p in arm.pats.iter() {
348 constrain_bindings_in_pat(&**p, rcx);
351 visit::walk_arm(rcx, arm, ());
354 fn visit_local(rcx: &mut Rcx, l: &ast::Local) {
356 constrain_bindings_in_pat(&*l.pat, rcx);
358 visit::walk_local(rcx, l, ());
361 fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) {
362 let tcx = rcx.fcx.tcx();
363 debug!("regionck::visit_pat(pat={})", pat.repr(tcx));
364 pat_util::pat_bindings(&tcx.def_map, pat, |_, id, span, _| {
365 // If we have a variable that contains region'd data, that
366 // data will be accessible from anywhere that the variable is
367 // accessed. We must be wary of loops like this:
369 // // from src/test/compile-fail/borrowck-lend-flow.rs
370 // let mut v = box 3, w = box 4;
371 // let mut x = &mut w;
374 // borrow(v); //~ ERROR cannot borrow
375 // x = &mut v; // (1)
378 // Typically, we try to determine the region of a borrow from
379 // those points where it is dereferenced. In this case, one
380 // might imagine that the lifetime of `x` need only be the
381 // body of the loop. But of course this is incorrect because
382 // the pointer that is created at point (1) is consumed at
383 // point (2), meaning that it must be live across the loop
384 // iteration. The easiest way to guarantee this is to require
385 // that the lifetime of any regions that appear in a
386 // variable's type enclose at least the variable's scope.
388 let var_region = tcx.region_maps.var_region(id);
389 constrain_regions_in_type_of_node(
391 infer::BindingTypeIsNotValidAtDecl(span));
395 fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
396 debug!("regionck::visit_expr(e={}, repeating_scope={:?})",
397 expr.repr(rcx.fcx.tcx()), rcx.repeating_scope);
399 let method_call = MethodCall::expr(expr.id);
400 let has_method_map = rcx.fcx.inh.method_map.borrow().contains_key(&method_call);
402 // Check any autoderefs or autorefs that appear.
403 for &adjustment in rcx.fcx.inh.adjustments.borrow().find(&expr.id).iter() {
404 debug!("adjustment={:?}", adjustment);
406 ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: opt_autoref}) => {
407 let expr_ty = rcx.resolve_node_type(expr.id);
408 constrain_autoderefs(rcx, expr, autoderefs, expr_ty);
409 for autoref in opt_autoref.iter() {
410 link_autoref(rcx, expr, autoderefs, autoref);
412 // Require that the resulting region encompasses
415 // FIXME(#6268) remove to support nested method calls
416 constrain_regions_in_type_of_node(
417 rcx, expr.id, ty::ReScope(expr.id),
418 infer::AutoBorrow(expr.span));
421 ty::AutoObject(ty::RegionTraitStore(trait_region, _), _, _, _) => {
422 // Determine if we are casting `expr` to a trait
423 // instance. If so, we have to be sure that the type of
424 // the source obeys the trait's region bound.
426 // Note: there is a subtle point here concerning type
427 // parameters. It is possible that the type of `source`
428 // contains type parameters, which in turn may contain
429 // regions that are not visible to us (only the caller
430 // knows about them). The kind checker is ultimately
431 // responsible for guaranteeing region safety in that
432 // particular case. There is an extensive comment on the
433 // function check_cast_for_escaping_regions() in kind.rs
434 // explaining how it goes about doing that.
436 let source_ty = rcx.resolve_node_type(expr.id);
437 constrain_regions_in_type(rcx, trait_region,
438 infer::RelateObjectBound(expr.span), source_ty);
445 ast::ExprCall(ref callee, ref args) => {
447 constrain_call(rcx, None, expr, Some(*callee),
448 args.as_slice(), false);
450 constrain_callee(rcx, callee.id, expr, &**callee);
459 visit::walk_expr(rcx, expr, ());
462 ast::ExprMethodCall(_, _, ref args) => {
463 constrain_call(rcx, None, expr, Some(*args.get(0)),
464 args.slice_from(1), false);
466 visit::walk_expr(rcx, expr, ());
469 ast::ExprAssign(ref lhs, _) => {
470 adjust_borrow_kind_for_assignment_lhs(rcx, &**lhs);
471 visit::walk_expr(rcx, expr, ());
474 ast::ExprAssignOp(_, ref lhs, ref rhs) => {
476 constrain_call(rcx, None, expr, Some(lhs.clone()),
477 [rhs.clone()], true);
480 adjust_borrow_kind_for_assignment_lhs(rcx, &**lhs);
482 visit::walk_expr(rcx, expr, ());
485 ast::ExprIndex(ref lhs, ref rhs) |
486 ast::ExprBinary(_, ref lhs, ref rhs) if has_method_map => {
487 // As `expr_method_call`, but the call is via an
488 // overloaded op. Note that we (sadly) currently use an
489 // implicit "by ref" sort of passing style here. This
490 // should be converted to an adjustment!
491 constrain_call(rcx, None, expr, Some(lhs.clone()),
492 [rhs.clone()], true);
494 visit::walk_expr(rcx, expr, ());
497 ast::ExprUnary(_, ref lhs) if has_method_map => {
499 constrain_call(rcx, None, expr, Some(lhs.clone()), [], true);
501 visit::walk_expr(rcx, expr, ());
504 ast::ExprUnary(ast::UnDeref, ref base) => {
505 // For *a, the lifetime of a must enclose the deref
506 let method_call = MethodCall::expr(expr.id);
507 let base_ty = match rcx.fcx.inh.method_map.borrow().find(&method_call) {
509 constrain_call(rcx, None, expr, Some(base.clone()), [], true);
510 ty::ty_fn_ret(method.ty)
512 None => rcx.resolve_node_type(base.id)
514 match ty::get(base_ty).sty {
515 ty::ty_rptr(r_ptr, _) => {
516 mk_subregion_due_to_dereference(rcx, expr.span,
517 ty::ReScope(expr.id), r_ptr);
522 visit::walk_expr(rcx, expr, ());
525 ast::ExprIndex(ref vec_expr, _) => {
526 // For a[b], the lifetime of a must enclose the deref
527 let vec_type = rcx.resolve_expr_type_adjusted(&**vec_expr);
528 constrain_index(rcx, expr, vec_type);
530 visit::walk_expr(rcx, expr, ());
533 ast::ExprCast(ref source, _) => {
534 // Determine if we are casting `source` to a trait
535 // instance. If so, we have to be sure that the type of
536 // the source obeys the trait's region bound.
538 // Note: there is a subtle point here concerning type
539 // parameters. It is possible that the type of `source`
540 // contains type parameters, which in turn may contain
541 // regions that are not visible to us (only the caller
542 // knows about them). The kind checker is ultimately
543 // responsible for guaranteeing region safety in that
544 // particular case. There is an extensive comment on the
545 // function check_cast_for_escaping_regions() in kind.rs
546 // explaining how it goes about doing that.
547 let target_ty = rcx.resolve_node_type(expr.id);
548 match ty::get(target_ty).sty {
549 ty::ty_rptr(trait_region, ty::mt{ty, ..}) => {
550 match ty::get(ty).sty {
551 ty::ty_trait(..) => {
552 let source_ty = rcx.resolve_expr_type_adjusted(&**source);
553 constrain_regions_in_type(
556 infer::RelateObjectBound(expr.span),
565 visit::walk_expr(rcx, expr, ());
568 ast::ExprAddrOf(m, ref base) => {
569 link_addr_of(rcx, expr, m, &**base);
571 // Require that when you write a `&expr` expression, the
572 // resulting pointer has a lifetime that encompasses the
573 // `&expr` expression itself. Note that we constraining
574 // the type of the node expr.id here *before applying
577 // FIXME(#6268) nested method calls requires that this rule change
578 let ty0 = rcx.resolve_node_type(expr.id);
579 constrain_regions_in_type(rcx, ty::ReScope(expr.id),
580 infer::AddrOf(expr.span), ty0);
581 visit::walk_expr(rcx, expr, ());
584 ast::ExprMatch(ref discr, ref arms) => {
585 link_match(rcx, &**discr, arms.as_slice());
587 visit::walk_expr(rcx, expr, ());
590 ast::ExprFnBlock(_, ref body) | ast::ExprProc(_, ref body) => {
591 check_expr_fn_block(rcx, expr, &**body);
594 ast::ExprLoop(ref body, _) => {
595 let repeating_scope = rcx.set_repeating_scope(body.id);
596 visit::walk_expr(rcx, expr, ());
597 rcx.set_repeating_scope(repeating_scope);
600 ast::ExprWhile(ref cond, ref body) => {
601 let repeating_scope = rcx.set_repeating_scope(cond.id);
602 rcx.visit_expr(&**cond, ());
604 rcx.set_repeating_scope(body.id);
605 rcx.visit_block(&**body, ());
607 rcx.set_repeating_scope(repeating_scope);
611 visit::walk_expr(rcx, expr, ());
616 fn check_expr_fn_block(rcx: &mut Rcx,
619 let tcx = rcx.fcx.tcx();
620 let function_type = rcx.resolve_node_type(expr.id);
621 match ty::get(function_type).sty {
622 ty::ty_closure(box ty::ClosureTy {
623 store: ty::RegionTraitStore(region, _), ..}) => {
624 freevars::with_freevars(tcx, expr.id, |freevars| {
625 if freevars.is_empty() {
626 // No free variables means that the environment
627 // will be NULL at runtime and hence the closure
628 // has static lifetime.
630 // Closure must not outlive the variables it closes over.
631 constrain_free_variables(rcx, region, expr, freevars);
633 // Closure cannot outlive the appropriate temporary scope.
634 let s = rcx.repeating_scope;
635 rcx.fcx.mk_subr(true, infer::InfStackClosure(expr.span),
636 region, ty::ReScope(s));
643 let repeating_scope = rcx.set_repeating_scope(body.id);
644 visit::walk_expr(rcx, expr, ());
645 rcx.set_repeating_scope(repeating_scope);
647 match ty::get(function_type).sty {
648 ty::ty_closure(box ty::ClosureTy {
649 store: ty::RegionTraitStore(..),
652 freevars::with_freevars(tcx, expr.id, |freevars| {
653 propagate_upupvar_borrow_kind(rcx, expr, freevars);
659 fn constrain_free_variables(rcx: &mut Rcx,
662 freevars: &[freevars::freevar_entry]) {
664 * Make sure that all free variables referenced inside the closure
665 * outlive the closure itself. Also, create an entry in the
666 * upvar_borrows map with a region.
669 let tcx = rcx.fcx.ccx.tcx;
670 let infcx = rcx.fcx.infcx();
671 debug!("constrain_free_variables({}, {})",
672 region.repr(tcx), expr.repr(tcx));
673 for freevar in freevars.iter() {
674 debug!("freevar def is {:?}", freevar.def);
676 // Identify the variable being closed over and its node-id.
677 let def = freevar.def;
678 let def_id = def.def_id();
679 assert!(def_id.krate == ast::LOCAL_CRATE);
680 let upvar_id = ty::UpvarId { var_id: def_id.node,
681 closure_expr_id: expr.id };
683 // Create a region variable to represent this borrow. This borrow
684 // must outlive the region on the closure.
685 let origin = infer::UpvarRegion(upvar_id, expr.span);
686 let freevar_region = infcx.next_region_var(origin);
687 rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node),
688 region, freevar_region);
690 // Create a UpvarBorrow entry. Note that we begin with a
691 // const borrow_kind, but change it to either mut or
692 // immutable as dictated by the uses.
693 let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow,
694 region: freevar_region };
695 rcx.fcx.inh.upvar_borrow_map.borrow_mut().insert(upvar_id,
698 // Guarantee that the closure does not outlive the variable itself.
699 let en_region = region_of_def(rcx.fcx, def);
700 debug!("en_region = {}", en_region.repr(tcx));
701 rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node),
706 fn propagate_upupvar_borrow_kind(rcx: &mut Rcx,
708 freevars: &[freevars::freevar_entry]) {
709 let tcx = rcx.fcx.ccx.tcx;
710 debug!("propagate_upupvar_borrow_kind({})", expr.repr(tcx));
711 for freevar in freevars.iter() {
712 // Because of the semi-hokey way that we are doing
713 // borrow_kind inference, we need to check for
714 // indirect dependencies, like so:
723 // Here, the `inner_call` is basically "reborrowing" the
724 // outer pointer. With no other changes, `inner_call`
725 // would infer that it requires a mutable borrow, but
726 // `outer_call` would infer that a const borrow is
727 // sufficient. This is because we haven't linked the
728 // borrow_kind of the borrow that occurs in the inner
729 // closure to the borrow_kind of the borrow in the outer
730 // closure. Note that regions *are* naturally linked
731 // because we have a proper inference scheme there.
733 // Anyway, for borrow_kind, we basically go back over now
734 // after checking the inner closure (and hence
735 // determining the final borrow_kind) and propagate that as
736 // a constraint on the outer closure.
738 def::DefUpvar(var_id, _, outer_closure_id, _) => {
739 // thing being captured is itself an upvar:
740 let outer_upvar_id = ty::UpvarId {
742 closure_expr_id: outer_closure_id };
743 let inner_upvar_id = ty::UpvarId {
745 closure_expr_id: expr.id };
746 link_upvar_borrow_kind_for_nested_closures(rcx,
756 fn constrain_callee(rcx: &mut Rcx,
757 callee_id: ast::NodeId,
758 call_expr: &ast::Expr,
759 callee_expr: &ast::Expr) {
760 let call_region = ty::ReScope(call_expr.id);
762 let callee_ty = rcx.resolve_node_type(callee_id);
763 match ty::get(callee_ty).sty {
764 ty::ty_bare_fn(..) => { }
765 ty::ty_closure(ref closure_ty) => {
766 let region = match closure_ty.store {
767 ty::RegionTraitStore(r, _) => {
768 // While we're here, link the closure's region with a unique
769 // immutable borrow (gathered later in borrowck)
770 let mc = mc::MemCategorizationContext::new(rcx);
771 let expr_cmt = ignore_err!(mc.cat_expr(callee_expr));
772 link_region(rcx, callee_expr.span, call_region,
773 ty::UniqueImmBorrow, expr_cmt);
776 ty::UniqTraitStore => ty::ReStatic
778 rcx.fcx.mk_subr(true, infer::InvokeClosure(callee_expr.span),
779 call_region, region);
782 // this should not happen, but it does if the program is
785 // tcx.sess.span_bug(
787 // format!("Calling non-function: {}", callee_ty.repr(tcx)));
792 fn constrain_call(rcx: &mut Rcx,
793 // might be expr_call, expr_method_call, or an overloaded
795 fn_expr_id: Option<ast::NodeId>,
796 call_expr: &ast::Expr,
797 receiver: Option<Gc<ast::Expr>>,
798 arg_exprs: &[Gc<ast::Expr>],
799 implicitly_ref_args: bool) {
800 //! Invoked on every call site (i.e., normal calls, method calls,
801 //! and overloaded operators). Constrains the regions which appear
802 //! in the type of the function. Also constrains the regions that
803 //! appear in the arguments appropriately.
805 let tcx = rcx.fcx.tcx();
806 debug!("constrain_call(call_expr={}, \
809 implicitly_ref_args={:?})",
813 implicitly_ref_args);
814 let callee_ty = match fn_expr_id {
815 Some(id) => rcx.resolve_node_type(id),
816 None => rcx.resolve_method_type(MethodCall::expr(call_expr.id))
817 .expect("call should have been to a method")
819 if ty::type_is_error(callee_ty) {
820 // Bail, as function type is unknown
823 let fn_sig = ty::ty_fn_sig(callee_ty);
825 // `callee_region` is the scope representing the time in which the
828 // FIXME(#6268) to support nested method calls, should be callee_id
829 let callee_scope = call_expr.id;
830 let callee_region = ty::ReScope(callee_scope);
832 for arg_expr in arg_exprs.iter() {
835 // ensure that any regions appearing in the argument type are
836 // valid for at least the lifetime of the function:
837 constrain_regions_in_type_of_node(
838 rcx, arg_expr.id, callee_region,
839 infer::CallArg(arg_expr.span));
841 // unfortunately, there are two means of taking implicit
842 // references, and we need to propagate constraints as a
843 // result. modes are going away and the "DerefArgs" code
844 // should be ported to use adjustments
845 if implicitly_ref_args {
846 link_by_ref(rcx, &**arg_expr, callee_scope);
850 // as loop above, but for receiver
851 for r in receiver.iter() {
853 constrain_regions_in_type_of_node(
854 rcx, r.id, callee_region, infer::CallRcvr(r.span));
855 if implicitly_ref_args {
856 link_by_ref(rcx, &**r, callee_scope);
860 // constrain regions that may appear in the return type to be
861 // valid for the function call:
862 constrain_regions_in_type(
863 rcx, callee_region, infer::CallReturn(call_expr.span),
867 fn constrain_autoderefs(rcx: &mut Rcx,
868 deref_expr: &ast::Expr,
870 mut derefd_ty: ty::t) {
872 * Invoked on any auto-dereference that occurs. Checks that if
873 * this is a region pointer being dereferenced, the lifetime of
874 * the pointer includes the deref expr.
876 let r_deref_expr = ty::ReScope(deref_expr.id);
877 for i in range(0u, derefs) {
878 debug!("constrain_autoderefs(deref_expr=?, derefd_ty={}, derefs={:?}/{:?}",
879 rcx.fcx.infcx().ty_to_str(derefd_ty),
882 let method_call = MethodCall::autoderef(deref_expr.id, i);
883 derefd_ty = match rcx.fcx.inh.method_map.borrow().find(&method_call) {
885 // Treat overloaded autoderefs as if an AutoRef adjustment
886 // was applied on the base type, as that is always the case.
887 let fn_sig = ty::ty_fn_sig(method.ty);
888 let self_ty = *fn_sig.inputs.get(0);
889 let (m, r) = match ty::get(self_ty).sty {
890 ty::ty_rptr(r, ref m) => (m.mutbl, r),
891 _ => rcx.tcx().sess.span_bug(deref_expr.span,
892 format!("bad overloaded deref type {}",
893 method.ty.repr(rcx.tcx())).as_slice())
896 let mc = mc::MemCategorizationContext::new(rcx);
897 let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
898 link_region(rcx, deref_expr.span, r,
899 ty::BorrowKind::from_mutbl(m), self_cmt);
902 // Specialized version of constrain_call.
903 constrain_regions_in_type(rcx, r_deref_expr,
904 infer::CallRcvr(deref_expr.span),
906 constrain_regions_in_type(rcx, r_deref_expr,
907 infer::CallReturn(deref_expr.span),
914 match ty::get(derefd_ty).sty {
915 ty::ty_rptr(r_ptr, _) => {
916 mk_subregion_due_to_dereference(rcx, deref_expr.span,
917 r_deref_expr, r_ptr);
922 match ty::deref(derefd_ty, true) {
923 Some(mt) => derefd_ty = mt.ty,
924 /* if this type can't be dereferenced, then there's already an error
925 in the session saying so. Just bail out for now */
931 pub fn mk_subregion_due_to_dereference(rcx: &mut Rcx,
933 minimum_lifetime: ty::Region,
934 maximum_lifetime: ty::Region) {
935 rcx.fcx.mk_subr(true, infer::DerefPointer(deref_span),
936 minimum_lifetime, maximum_lifetime)
940 fn constrain_index(rcx: &mut Rcx,
941 index_expr: &ast::Expr,
945 * Invoked on any index expression that occurs. Checks that if
946 * this is a slice being indexed, the lifetime of the pointer
947 * includes the deref expr.
950 debug!("constrain_index(index_expr=?, indexed_ty={}",
951 rcx.fcx.infcx().ty_to_str(indexed_ty));
953 let r_index_expr = ty::ReScope(index_expr.id);
954 match ty::get(indexed_ty).sty {
955 ty::ty_rptr(r_ptr, mt) => match ty::get(mt.ty).sty {
956 ty::ty_vec(_, None) | ty::ty_str => {
957 rcx.fcx.mk_subr(true, infer::IndexSlice(index_expr.span),
958 r_index_expr, r_ptr);
967 fn constrain_regions_in_type_of_node(
970 minimum_lifetime: ty::Region,
971 origin: infer::SubregionOrigin) {
972 //! Guarantees that any lifetimes which appear in the type of
973 //! the node `id` (after applying adjustments) are valid for at
974 //! least `minimum_lifetime`
976 let tcx = rcx.fcx.tcx();
978 // Try to resolve the type. If we encounter an error, then typeck
979 // is going to fail anyway, so just stop here and let typeck
980 // report errors later on in the writeback phase.
981 let ty0 = rcx.resolve_node_type(id);
982 let ty = ty::adjust_ty(tcx, origin.span(), id, ty0,
983 rcx.fcx.inh.adjustments.borrow().find(&id),
984 |method_call| rcx.resolve_method_type(method_call));
985 debug!("constrain_regions_in_type_of_node(\
986 ty={}, ty0={}, id={}, minimum_lifetime={:?})",
987 ty_to_str(tcx, ty), ty_to_str(tcx, ty0),
988 id, minimum_lifetime);
989 constrain_regions_in_type(rcx, minimum_lifetime, origin, ty);
992 fn constrain_regions_in_type(
994 minimum_lifetime: ty::Region,
995 origin: infer::SubregionOrigin,
998 * Requires that any regions which appear in `ty` must be
999 * superregions of `minimum_lifetime`. Also enforces the constraint
1000 * that given a pointer type `&'r T`, T must not contain regions
1001 * that outlive 'r, as well as analogous constraints for other
1004 * This check prevents regions from being used outside of the block in
1005 * which they are valid. Recall that regions represent blocks of
1006 * code or expressions: this requirement basically says "any place
1007 * that uses or may use a region R must be within the block of
1008 * code that R corresponds to."
1011 let tcx = rcx.fcx.ccx.tcx;
1013 debug!("constrain_regions_in_type(minimum_lifetime={}, ty={})",
1014 region_to_str(tcx, "", false, minimum_lifetime),
1015 ty_to_str(tcx, ty));
1017 relate_nested_regions(tcx, Some(minimum_lifetime), ty, |r_sub, r_sup| {
1018 debug!("relate_nested_regions(r_sub={}, r_sup={})",
1022 if r_sup.is_bound() || r_sub.is_bound() {
1023 // a bound region is one which appears inside an fn type.
1024 // (e.g., the `&` in `fn(&T)`). Such regions need not be
1025 // constrained by `minimum_lifetime` as they are placeholders
1026 // for regions that are as-yet-unknown.
1027 } else if r_sub == minimum_lifetime {
1029 true, origin.clone(),
1033 true, infer::ReferenceOutlivesReferent(ty, origin.span()),
1039 fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
1040 mutability: ast::Mutability, base: &ast::Expr) {
1042 * Computes the guarantor for an expression `&base` and then
1043 * ensures that the lifetime of the resulting pointer is linked
1044 * to the lifetime of its guarantor (if any).
1047 debug!("link_addr_of(base=?)");
1050 let mc = mc::MemCategorizationContext::new(rcx);
1051 ignore_err!(mc.cat_expr(base))
1053 link_region_from_node_type(rcx, expr.span, expr.id, mutability, cmt);
1056 fn link_local(rcx: &Rcx, local: &ast::Local) {
1058 * Computes the guarantors for any ref bindings in a `let` and
1059 * then ensures that the lifetime of the resulting pointer is
1060 * linked to the lifetime of the initialization expression.
1063 debug!("regionck::for_local()");
1064 let init_expr = match local.init {
1066 Some(ref expr) => expr,
1068 let mc = mc::MemCategorizationContext::new(rcx);
1069 let discr_cmt = ignore_err!(mc.cat_expr(&**init_expr));
1070 link_pattern(rcx, mc, discr_cmt, &*local.pat);
1073 fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) {
1075 * Computes the guarantors for any ref bindings in a match and
1076 * then ensures that the lifetime of the resulting pointer is
1077 * linked to the lifetime of its guarantor (if any).
1080 debug!("regionck::for_match()");
1081 let mc = mc::MemCategorizationContext::new(rcx);
1082 let discr_cmt = ignore_err!(mc.cat_expr(discr));
1083 debug!("discr_cmt={}", discr_cmt.repr(rcx.tcx()));
1084 for arm in arms.iter() {
1085 for root_pat in arm.pats.iter() {
1086 link_pattern(rcx, mc, discr_cmt.clone(), &**root_pat);
1091 fn link_pattern(rcx: &Rcx,
1092 mc: mc::MemCategorizationContext<Rcx>,
1094 root_pat: &ast::Pat) {
1096 * Link lifetimes of any ref bindings in `root_pat` to
1097 * the pointers found in the discriminant, if needed.
1100 let _ = mc.cat_pattern(discr_cmt, root_pat, |mc, sub_cmt, sub_pat| {
1101 match sub_pat.node {
1103 ast::PatIdent(ast::BindByRef(mutbl), _, _) => {
1104 link_region_from_node_type(
1105 rcx, sub_pat.span, sub_pat.id,
1109 // `[_, ..slice, _]` pattern
1110 ast::PatVec(_, Some(ref slice_pat), _) => {
1111 match mc.cat_slice_pattern(sub_cmt, &**slice_pat) {
1112 Ok((slice_cmt, slice_mutbl, slice_r)) => {
1113 link_region(rcx, sub_pat.span, slice_r,
1114 ty::BorrowKind::from_mutbl(slice_mutbl),
1125 fn link_autoref(rcx: &Rcx,
1128 autoref: &ty::AutoRef) {
1130 * Link lifetime of borrowed pointer resulting from autoref
1131 * to lifetimes in the value being autoref'd.
1134 debug!("link_autoref(autoref={:?})", autoref);
1135 let mc = mc::MemCategorizationContext::new(rcx);
1136 let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
1137 debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx()));
1140 ty::AutoPtr(r, m) => {
1141 link_region(rcx, expr.span, r,
1142 ty::BorrowKind::from_mutbl(m), expr_cmt);
1145 ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => {
1146 let cmt_index = mc.cat_index(expr, expr_cmt, autoderefs+1);
1147 link_region(rcx, expr.span, r,
1148 ty::BorrowKind::from_mutbl(m), cmt_index);
1151 ty::AutoBorrowObj(r, m) => {
1152 let cmt_deref = mc.cat_deref_obj(expr, expr_cmt);
1153 link_region(rcx, expr.span, r,
1154 ty::BorrowKind::from_mutbl(m), cmt_deref);
1157 ty::AutoUnsafe(_) => {}
1161 fn link_by_ref(rcx: &Rcx,
1163 callee_scope: ast::NodeId) {
1165 * Computes the guarantor for cases where the `expr` is
1166 * being passed by implicit reference and must outlive
1170 let tcx = rcx.tcx();
1171 debug!("link_by_ref(expr={}, callee_scope={})",
1172 expr.repr(tcx), callee_scope);
1173 let mc = mc::MemCategorizationContext::new(rcx);
1174 let expr_cmt = ignore_err!(mc.cat_expr(expr));
1175 let region_min = ty::ReScope(callee_scope);
1176 link_region(rcx, expr.span, region_min, ty::ImmBorrow, expr_cmt);
1179 fn link_region_from_node_type(rcx: &Rcx,
1182 mutbl: ast::Mutability,
1183 cmt_borrowed: mc::cmt) {
1185 * Like `link_region()`, except that the region is
1186 * extracted from the type of `id`, which must be some
1187 * reference (`&T`, `&str`, etc).
1190 let rptr_ty = rcx.resolve_node_type(id);
1191 if !ty::type_is_bot(rptr_ty) && !ty::type_is_error(rptr_ty) {
1192 let tcx = rcx.fcx.ccx.tcx;
1193 debug!("rptr_ty={}", ty_to_str(tcx, rptr_ty));
1194 let r = ty::ty_region(tcx, span, rptr_ty);
1195 link_region(rcx, span, r, ty::BorrowKind::from_mutbl(mutbl),
1200 fn link_region(rcx: &Rcx,
1202 region_min: ty::Region,
1203 kind: ty::BorrowKind,
1204 cmt_borrowed: mc::cmt) {
1206 * Informs the inference engine that a borrow of `cmt`
1207 * must have the borrow kind `kind` and lifetime `region_min`.
1208 * If `cmt` is a deref of a region pointer with
1209 * lifetime `r_borrowed`, this will add the constraint that
1210 * `region_min <= r_borrowed`.
1213 // Iterate through all the things that must be live at least
1214 // for the lifetime `region_min` for the borrow to be valid:
1215 let mut cmt_borrowed = cmt_borrowed;
1217 debug!("link_region(region_min={}, kind={}, cmt_borrowed={})",
1218 region_min.repr(rcx.tcx()),
1219 kind.repr(rcx.tcx()),
1220 cmt_borrowed.repr(rcx.tcx()));
1221 match cmt_borrowed.cat.clone() {
1222 mc::cat_deref(base, _, mc::BorrowedPtr(_, r_borrowed)) => {
1223 // References to an upvar `x` are translated to
1224 // `*x`, since that is what happens in the
1225 // underlying machine. We detect such references
1226 // and treat them slightly differently, both to
1227 // offer better error messages and because we need
1228 // to infer the kind of borrow (mut, const, etc)
1229 // to use for each upvar.
1230 let cause = match base.cat {
1231 mc::cat_upvar(ref upvar_id, _) => {
1232 match rcx.fcx.inh.upvar_borrow_map.borrow_mut()
1233 .find_mut(upvar_id) {
1234 Some(upvar_borrow) => {
1235 debug!("link_region: {} <= {}",
1236 region_min.repr(rcx.tcx()),
1237 upvar_borrow.region.repr(rcx.tcx()));
1238 adjust_upvar_borrow_kind_for_loan(
1242 infer::ReborrowUpvar(span, *upvar_id)
1245 rcx.tcx().sess.span_bug(
1247 format!("Illegal upvar id: {}",
1249 rcx.tcx())).as_slice());
1255 infer::Reborrow(span)
1259 debug!("link_region: {} <= {}",
1260 region_min.repr(rcx.tcx()),
1261 r_borrowed.repr(rcx.tcx()));
1262 rcx.fcx.mk_subr(true, cause, region_min, r_borrowed);
1264 if kind != ty::ImmBorrow {
1265 // If this is a mutable borrow, then the thing
1266 // being borrowed will have to be unique.
1267 // In user code, this means it must be an `&mut`
1268 // borrow, but for an upvar, we might opt
1269 // for an immutable-unique borrow.
1270 adjust_upvar_borrow_kind_for_unique(rcx, base);
1273 // Borrowing an `&mut` pointee for `region_min` is
1274 // only valid if the pointer resides in a unique
1275 // location which is itself valid for
1276 // `region_min`. We don't care about the unique
1277 // part, but we may need to influence the
1278 // inference to ensure that the location remains
1281 // FIXME(#8624) fixing borrowck will require this
1282 // if m == ast::m_mutbl {
1283 // cmt_borrowed = cmt_base;
1289 mc::cat_discr(cmt_base, _) |
1290 mc::cat_downcast(cmt_base) |
1291 mc::cat_deref(cmt_base, _, mc::GcPtr(..)) |
1292 mc::cat_deref(cmt_base, _, mc::OwnedPtr) |
1293 mc::cat_interior(cmt_base, _) => {
1294 // Interior or owned data requires its base to be valid
1295 cmt_borrowed = cmt_base;
1297 mc::cat_deref(_, _, mc::UnsafePtr(..)) |
1298 mc::cat_static_item |
1299 mc::cat_copied_upvar(..) |
1303 mc::cat_rvalue(..) => {
1304 // These are all "base cases" with independent lifetimes
1305 // that are not subject to inference
1312 fn adjust_borrow_kind_for_assignment_lhs(rcx: &Rcx,
1315 * Adjusts the inferred borrow_kind as needed to account
1316 * for upvars that are assigned to in an assignment
1320 let mc = mc::MemCategorizationContext::new(rcx);
1321 let cmt = ignore_err!(mc.cat_expr(lhs));
1322 adjust_upvar_borrow_kind_for_mut(rcx, cmt);
1325 fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx,
1329 debug!("adjust_upvar_borrow_kind_for_mut(cmt={})",
1330 cmt.repr(rcx.tcx()));
1332 match cmt.cat.clone() {
1333 mc::cat_deref(base, _, mc::OwnedPtr) |
1334 mc::cat_interior(base, _) |
1335 mc::cat_downcast(base) |
1336 mc::cat_discr(base, _) => {
1337 // Interior or owned data is mutable if base is
1338 // mutable, so iterate to the base.
1343 mc::cat_deref(base, _, mc::BorrowedPtr(..)) => {
1345 mc::cat_upvar(ref upvar_id, _) => {
1346 // if this is an implicit deref of an
1347 // upvar, then we need to modify the
1348 // borrow_kind of the upvar to make sure it
1349 // is inferred to mutable if necessary
1350 let mut upvar_borrow_map =
1351 rcx.fcx.inh.upvar_borrow_map.borrow_mut();
1352 let ub = upvar_borrow_map.get_mut(upvar_id);
1353 return adjust_upvar_borrow_kind(*upvar_id, ub, ty::MutBorrow);
1359 // assignment to deref of an `&mut`
1360 // borrowed pointer implies that the
1361 // pointer itself must be unique, but not
1362 // necessarily *mutable*
1363 return adjust_upvar_borrow_kind_for_unique(rcx, base);
1366 mc::cat_deref(_, _, mc::UnsafePtr(..)) |
1367 mc::cat_deref(_, _, mc::GcPtr) |
1368 mc::cat_static_item |
1370 mc::cat_copied_upvar(_) |
1373 mc::cat_upvar(..) => {
1380 fn adjust_upvar_borrow_kind_for_unique(rcx: &Rcx, cmt: mc::cmt) {
1383 debug!("adjust_upvar_borrow_kind_for_unique(cmt={})",
1384 cmt.repr(rcx.tcx()));
1386 match cmt.cat.clone() {
1387 mc::cat_deref(base, _, mc::OwnedPtr) |
1388 mc::cat_interior(base, _) |
1389 mc::cat_downcast(base) |
1390 mc::cat_discr(base, _) => {
1391 // Interior or owned data is unique if base is
1397 mc::cat_deref(base, _, mc::BorrowedPtr(..)) => {
1399 mc::cat_upvar(ref upvar_id, _) => {
1400 // if this is an implicit deref of an
1401 // upvar, then we need to modify the
1402 // borrow_kind of the upvar to make sure it
1403 // is inferred to unique if necessary
1404 let mut ub = rcx.fcx.inh.upvar_borrow_map.borrow_mut();
1405 let ub = ub.get_mut(upvar_id);
1406 return adjust_upvar_borrow_kind(*upvar_id, ub, ty::UniqueImmBorrow);
1412 // for a borrowed pointer to be unique, its
1413 // base must be unique
1414 return adjust_upvar_borrow_kind_for_unique(rcx, base);
1417 mc::cat_deref(_, _, mc::UnsafePtr(..)) |
1418 mc::cat_deref(_, _, mc::GcPtr) |
1419 mc::cat_static_item |
1421 mc::cat_copied_upvar(_) |
1424 mc::cat_upvar(..) => {
1431 fn link_upvar_borrow_kind_for_nested_closures(rcx: &mut Rcx,
1432 inner_upvar_id: ty::UpvarId,
1433 outer_upvar_id: ty::UpvarId) {
1435 * Indicates that the borrow_kind of `outer_upvar_id` must
1436 * permit a reborrowing with the borrow_kind of `inner_upvar_id`.
1437 * This occurs in nested closures, see comment above at the call to
1441 debug!("link_upvar_borrow_kind: inner_upvar_id={:?} outer_upvar_id={:?}",
1442 inner_upvar_id, outer_upvar_id);
1444 let mut upvar_borrow_map = rcx.fcx.inh.upvar_borrow_map.borrow_mut();
1445 let inner_borrow = upvar_borrow_map.get_copy(&inner_upvar_id);
1446 match upvar_borrow_map.find_mut(&outer_upvar_id) {
1447 Some(outer_borrow) => {
1448 adjust_upvar_borrow_kind(outer_upvar_id, outer_borrow, inner_borrow.kind);
1450 None => { /* outer closure is not a stack closure */ }
1454 fn adjust_upvar_borrow_kind_for_loan(upvar_id: ty::UpvarId,
1455 upvar_borrow: &mut ty::UpvarBorrow,
1456 kind: ty::BorrowKind) {
1457 debug!("adjust_upvar_borrow_kind_for_loan: upvar_id={:?} kind={:?} -> {:?}",
1458 upvar_id, upvar_borrow.kind, kind);
1460 adjust_upvar_borrow_kind(upvar_id, upvar_borrow, kind)
1463 fn adjust_upvar_borrow_kind(upvar_id: ty::UpvarId,
1464 upvar_borrow: &mut ty::UpvarBorrow,
1465 kind: ty::BorrowKind) {
1467 * We infer the borrow_kind with which to borrow upvars in a stack
1468 * closure. The borrow_kind basically follows a lattice of
1469 * `imm < unique-imm < mut`, moving from left to right as needed (but never
1470 * right to left). Here the argument `mutbl` is the borrow_kind that
1471 * is required by some particular use.
1474 debug!("adjust_upvar_borrow_kind: id={:?} kind=({:?} -> {:?})",
1475 upvar_id, upvar_borrow.kind, kind);
1477 match (upvar_borrow.kind, kind) {
1479 (ty::ImmBorrow, ty::UniqueImmBorrow) |
1480 (ty::ImmBorrow, ty::MutBorrow) |
1481 (ty::UniqueImmBorrow, ty::MutBorrow) => {
1482 upvar_borrow.kind = kind;
1485 (ty::ImmBorrow, ty::ImmBorrow) |
1486 (ty::UniqueImmBorrow, ty::ImmBorrow) |
1487 (ty::UniqueImmBorrow, ty::UniqueImmBorrow) |
1488 (ty::MutBorrow, _) => {