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::freevars;
123 use mc = middle::mem_categorization;
124 use middle::ty::{ReScope};
126 use middle::typeck::astconv::AstConv;
127 use middle::typeck::check::FnCtxt;
128 use middle::typeck::check::regionmanip::relate_nested_regions;
129 use middle::typeck::infer::resolve_and_force_all_but_regions;
130 use middle::typeck::infer::resolve_type;
131 use middle::typeck::infer;
132 use middle::typeck::MethodCall;
133 use middle::pat_util;
134 use util::ppaux::{ty_to_str, region_to_str, Repr};
136 use syntax::ast::{ManagedSigil, OwnedSigil, BorrowedSigil};
137 use syntax::ast::{DefArg, DefBinding, DefLocal, DefUpvar};
139 use syntax::ast_util;
140 use syntax::codemap::Span;
142 use syntax::visit::Visitor;
144 // If mem categorization results in an error, it's because the type
145 // check failed (or will fail, when the error is uncovered and
146 // reported during writeback). In this case, we just ignore this part
147 // of the code and don't try to add any more region constraints.
148 macro_rules! ignore_err(
159 errors_reported: uint,
161 // id of innermost fn or loop
162 repeating_scope: ast::NodeId,
165 fn region_of_def(fcx: &FnCtxt, def: ast::Def) -> ty::Region {
167 * Returns the validity region of `def` -- that is, how long
173 DefLocal(node_id, _) | DefArg(node_id, _) |
174 DefBinding(node_id, _) => {
175 tcx.region_maps.var_region(node_id)
177 DefUpvar(_, subdef, closure_id, body_id) => {
178 match ty::ty_closure_sigil(fcx.node_ty(closure_id)) {
179 BorrowedSigil => region_of_def(fcx, *subdef),
180 ManagedSigil | OwnedSigil => ReScope(body_id)
184 tcx.sess.bug(format!("unexpected def in region_of_def: {:?}",
191 pub fn tcx(&self) -> &'a ty::ctxt {
195 pub fn set_repeating_scope(&mut self, scope: ast::NodeId) -> ast::NodeId {
196 let old_scope = self.repeating_scope;
197 self.repeating_scope = scope;
201 pub fn resolve_type(&self, unresolved_ty: ty::t) -> ty::t {
203 * Try to resolve the type for the given node, returning
204 * t_err if an error results. Note that we never care
205 * about the details of the error, the same error will be
206 * detected and reported in the writeback phase.
208 * Note one important point: we do not attempt to resolve
209 * *region variables* here. This is because regionck is
210 * essentially adding constraints to those region variables
211 * and so may yet influence how they are resolved.
213 * Consider this silly example:
215 * fn borrow(x: &int) -> &int {x}
216 * fn foo(x: @int) -> int { // block: B
217 * let b = borrow(x); // region: <R0>
221 * Here, the region of `b` will be `<R0>`. `<R0>` is
222 * constrainted to be some subregion of the block B and some
223 * superregion of the call. If we forced it now, we'd choose
224 * the smaller region (the call). But that would make the *b
225 * illegal. Since we don't resolve, the type of b will be
226 * `&<R0>.int` and then `*b` will require that `<R0>` be
227 * bigger than the let and the `*b` expression, so we will
228 * effectively resolve `<R0>` to be the block B.
230 match resolve_type(self.fcx.infcx(), unresolved_ty,
231 resolve_and_force_all_but_regions) {
233 Err(_) => ty::mk_err()
237 /// Try to resolve the type for the given node.
238 fn resolve_node_type(&mut self, id: ast::NodeId) -> ty::t {
239 let t = self.fcx.node_ty(id);
243 fn resolve_method_type(&self, method_call: MethodCall) -> Option<ty::t> {
244 let method_ty = self.fcx.inh.method_map.borrow().get()
245 .find(&method_call).map(|method| method.ty);
246 method_ty.map(|method_ty| self.resolve_type(method_ty))
249 /// Try to resolve the type for the given node.
250 pub fn resolve_expr_type_adjusted(&mut self, expr: &ast::Expr) -> ty::t {
251 let ty_unadjusted = self.resolve_node_type(expr.id);
252 if ty::type_is_error(ty_unadjusted) || ty::type_is_bot(ty_unadjusted) {
255 let tcx = self.fcx.tcx();
256 let adjustment = self.fcx.inh.adjustments.borrow().get().find_copy(&expr.id);
257 ty::adjust_ty(tcx, expr.span, expr.id, ty_unadjusted, adjustment,
258 |method_call| self.resolve_method_type(method_call))
263 impl<'a, 'b> mc::Typer for &'a mut Rcx<'b> {
264 fn tcx<'a>(&'a self) -> &'a ty::ctxt {
268 fn node_ty(&mut self, id: ast::NodeId) -> mc::McResult<ty::t> {
269 let t = self.resolve_node_type(id);
270 if ty::type_is_error(t) {Err(())} else {Ok(t)}
273 fn node_method_ty(&self, method_call: MethodCall) -> Option<ty::t> {
274 self.resolve_method_type(method_call)
277 fn adjustment(&mut self, id: ast::NodeId) -> Option<@ty::AutoAdjustment> {
278 let adjustments = self.fcx.inh.adjustments.borrow();
279 adjustments.get().find_copy(&id)
282 fn is_method_call(&mut self, id: ast::NodeId) -> bool {
283 self.fcx.inh.method_map.borrow().get().contains_key(&MethodCall::expr(id))
286 fn temporary_scope(&mut self, id: ast::NodeId) -> Option<ast::NodeId> {
287 self.tcx().region_maps.temporary_scope(id)
290 fn upvar_borrow(&mut self, id: ty::UpvarId) -> ty::UpvarBorrow {
291 let upvar_borrow_map = self.fcx.inh.upvar_borrow_map.borrow();
292 upvar_borrow_map.get().get_copy(&id)
296 pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) {
297 let mut rcx = Rcx { fcx: fcx, errors_reported: 0,
298 repeating_scope: e.id };
300 if fcx.err_count_since_creation() == 0 {
301 // regionck assumes typeck succeeded
302 rcx.visit_expr(e, ());
304 fcx.infcx().resolve_regions();
307 pub fn regionck_fn(fcx: &FnCtxt, blk: &ast::Block) {
308 let mut rcx = Rcx { fcx: fcx, errors_reported: 0,
309 repeating_scope: blk.id };
311 if fcx.err_count_since_creation() == 0 {
312 // regionck assumes typeck succeeded
313 rcx.visit_block(blk, ());
315 fcx.infcx().resolve_regions();
318 impl<'a> Visitor<()> for Rcx<'a> {
319 // (..) FIXME(#3238) should use visit_pat, not visit_arm/visit_local,
320 // However, right now we run into an issue whereby some free
321 // regions are not properly related if they appear within the
322 // types of arguments that must be inferred. This could be
323 // addressed by deferring the construction of the region
324 // hierarchy, and in particular the relationships between free
325 // regions, until regionck, as described in #3238.
327 fn visit_item(&mut self, i: &ast::Item, _: ()) { visit_item(self, i); }
329 fn visit_expr(&mut self, ex: &ast::Expr, _: ()) { visit_expr(self, ex); }
331 //visit_pat: visit_pat, // (..) see above
333 fn visit_arm(&mut self, a: &ast::Arm, _: ()) { visit_arm(self, a); }
335 fn visit_local(&mut self, l: &ast::Local, _: ()) { visit_local(self, l); }
337 fn visit_block(&mut self, b: &ast::Block, _: ()) { visit_block(self, b); }
340 fn visit_item(_rcx: &mut Rcx, _item: &ast::Item) {
344 fn visit_block(rcx: &mut Rcx, b: &ast::Block) {
345 visit::walk_block(rcx, b, ());
348 fn visit_arm(rcx: &mut Rcx, arm: &ast::Arm) {
350 for &p in arm.pats.iter() {
351 constrain_bindings_in_pat(p, rcx);
354 visit::walk_arm(rcx, arm, ());
357 fn visit_local(rcx: &mut Rcx, l: &ast::Local) {
359 constrain_bindings_in_pat(l.pat, rcx);
361 visit::walk_local(rcx, l, ());
364 fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) {
365 let tcx = rcx.fcx.tcx();
366 debug!("regionck::visit_pat(pat={})", pat.repr(tcx));
367 pat_util::pat_bindings(tcx.def_map, pat, |_, id, span, _| {
368 // If we have a variable that contains region'd data, that
369 // data will be accessible from anywhere that the variable is
370 // accessed. We must be wary of loops like this:
372 // // from src/test/compile-fail/borrowck-lend-flow.rs
373 // let mut v = ~3, w = ~4;
374 // let mut x = &mut w;
377 // borrow(v); //~ ERROR cannot borrow
378 // x = &mut v; // (1)
381 // Typically, we try to determine the region of a borrow from
382 // those points where it is dereferenced. In this case, one
383 // might imagine that the lifetime of `x` need only be the
384 // body of the loop. But of course this is incorrect because
385 // the pointer that is created at point (1) is consumed at
386 // point (2), meaning that it must be live across the loop
387 // iteration. The easiest way to guarantee this is to require
388 // that the lifetime of any regions that appear in a
389 // variable's type enclose at least the variable's scope.
391 let var_region = tcx.region_maps.var_region(id);
392 constrain_regions_in_type_of_node(
394 infer::BindingTypeIsNotValidAtDecl(span));
398 fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
399 debug!("regionck::visit_expr(e={}, repeating_scope={:?})",
400 expr.repr(rcx.fcx.tcx()), rcx.repeating_scope);
402 let method_call = MethodCall::expr(expr.id);
403 let has_method_map = rcx.fcx.inh.method_map.get().contains_key(&method_call);
405 // Check any autoderefs or autorefs that appear.
406 for &adjustment in rcx.fcx.inh.adjustments.borrow().get().find(&expr.id).iter() {
407 debug!("adjustment={:?}", adjustment);
409 ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: opt_autoref}) => {
410 let expr_ty = rcx.resolve_node_type(expr.id);
411 constrain_autoderefs(rcx, expr, autoderefs, expr_ty);
412 for autoref in opt_autoref.iter() {
413 link_autoref(rcx, expr, autoderefs, autoref);
415 // Require that the resulting region encompasses
418 // FIXME(#6268) remove to support nested method calls
419 constrain_regions_in_type_of_node(
420 rcx, expr.id, ty::ReScope(expr.id),
421 infer::AutoBorrow(expr.span));
424 ty::AutoObject(ast::BorrowedSigil, Some(trait_region), _, _, _, _) => {
425 // Determine if we are casting `expr` to an trait
426 // instance. If so, we have to be sure that the type of
427 // the source obeys the trait's region bound.
429 // Note: there is a subtle point here concerning type
430 // parameters. It is possible that the type of `source`
431 // contains type parameters, which in turn may contain
432 // regions that are not visible to us (only the caller
433 // knows about them). The kind checker is ultimately
434 // responsible for guaranteeing region safety in that
435 // particular case. There is an extensive comment on the
436 // function check_cast_for_escaping_regions() in kind.rs
437 // explaining how it goes about doing that.
439 let source_ty = rcx.fcx.expr_ty(expr);
440 constrain_regions_in_type(rcx, trait_region,
441 infer::RelateObjectBound(expr.span), source_ty);
448 ast::ExprCall(callee, ref args) => {
449 constrain_callee(rcx, callee.id, expr, callee);
457 visit::walk_expr(rcx, expr, ());
460 ast::ExprMethodCall(_, _, ref args) => {
461 constrain_call(rcx, None, expr, Some(*args.get(0)),
462 args.slice_from(1), false);
464 visit::walk_expr(rcx, expr, ());
467 ast::ExprAssign(lhs, _) => {
468 adjust_borrow_kind_for_assignment_lhs(rcx, lhs);
469 visit::walk_expr(rcx, expr, ());
472 ast::ExprAssignOp(_, lhs, rhs) => {
474 constrain_call(rcx, None, expr, Some(lhs), [rhs], true);
477 adjust_borrow_kind_for_assignment_lhs(rcx, lhs);
479 visit::walk_expr(rcx, expr, ());
482 ast::ExprIndex(lhs, rhs) |
483 ast::ExprBinary(_, lhs, rhs) if has_method_map => {
484 // As `expr_method_call`, but the call is via an
485 // overloaded op. Note that we (sadly) currently use an
486 // implicit "by ref" sort of passing style here. This
487 // should be converted to an adjustment!
488 constrain_call(rcx, None, expr, Some(lhs), [rhs], true);
490 visit::walk_expr(rcx, expr, ());
493 ast::ExprUnary(_, lhs) if has_method_map => {
495 constrain_call(rcx, None, expr, Some(lhs), [], true);
497 visit::walk_expr(rcx, expr, ());
500 ast::ExprUnary(ast::UnDeref, base) => {
501 // For *a, the lifetime of a must enclose the deref
502 let method_call = MethodCall::expr(expr.id);
503 let base_ty = match rcx.fcx.inh.method_map.get().find(&method_call) {
505 constrain_call(rcx, None, expr, Some(base), [], true);
506 ty::ty_fn_ret(method.ty)
508 None => rcx.resolve_node_type(base.id)
510 match ty::get(base_ty).sty {
511 ty::ty_rptr(r_ptr, _) => {
512 mk_subregion_due_to_dereference(rcx, expr.span,
513 ty::ReScope(expr.id), r_ptr);
518 visit::walk_expr(rcx, expr, ());
521 ast::ExprIndex(vec_expr, _) => {
522 // For a[b], the lifetime of a must enclose the deref
523 let vec_type = rcx.resolve_expr_type_adjusted(vec_expr);
524 constrain_index(rcx, expr, vec_type);
526 visit::walk_expr(rcx, expr, ());
529 ast::ExprCast(source, _) => {
530 // Determine if we are casting `source` to an trait
531 // instance. If so, we have to be sure that the type of
532 // the source obeys the trait's region bound.
534 // Note: there is a subtle point here concerning type
535 // parameters. It is possible that the type of `source`
536 // contains type parameters, which in turn may contain
537 // regions that are not visible to us (only the caller
538 // knows about them). The kind checker is ultimately
539 // responsible for guaranteeing region safety in that
540 // particular case. There is an extensive comment on the
541 // function check_cast_for_escaping_regions() in kind.rs
542 // explaining how it goes about doing that.
543 let target_ty = rcx.resolve_node_type(expr.id);
544 match ty::get(target_ty).sty {
545 ty::ty_trait(~ty::TyTrait { store: ty::RegionTraitStore(trait_region), .. }) => {
546 let source_ty = rcx.resolve_expr_type_adjusted(source);
547 constrain_regions_in_type(
550 infer::RelateObjectBound(expr.span),
556 visit::walk_expr(rcx, expr, ());
559 ast::ExprAddrOf(m, base) => {
560 link_addr_of(rcx, expr, m, base);
562 // Require that when you write a `&expr` expression, the
563 // resulting pointer has a lifetime that encompasses the
564 // `&expr` expression itself. Note that we constraining
565 // the type of the node expr.id here *before applying
568 // FIXME(#6268) nested method calls requires that this rule change
569 let ty0 = rcx.resolve_node_type(expr.id);
570 constrain_regions_in_type(rcx, ty::ReScope(expr.id),
571 infer::AddrOf(expr.span), ty0);
572 visit::walk_expr(rcx, expr, ());
575 ast::ExprMatch(discr, ref arms) => {
576 link_match(rcx, discr, arms.as_slice());
578 visit::walk_expr(rcx, expr, ());
581 ast::ExprFnBlock(_, ref body) | ast::ExprProc(_, ref body) => {
582 check_expr_fn_block(rcx, expr, &**body);
585 ast::ExprLoop(body, _) => {
586 let repeating_scope = rcx.set_repeating_scope(body.id);
587 visit::walk_expr(rcx, expr, ());
588 rcx.set_repeating_scope(repeating_scope);
591 ast::ExprWhile(cond, body) => {
592 let repeating_scope = rcx.set_repeating_scope(cond.id);
593 rcx.visit_expr(cond, ());
595 rcx.set_repeating_scope(body.id);
596 rcx.visit_block(body, ());
598 rcx.set_repeating_scope(repeating_scope);
602 visit::walk_expr(rcx, expr, ());
607 fn check_expr_fn_block(rcx: &mut Rcx,
610 let tcx = rcx.fcx.tcx();
611 let function_type = rcx.resolve_node_type(expr.id);
612 match ty::get(function_type).sty {
613 ty::ty_closure(~ty::ClosureTy {
614 sigil: ast::BorrowedSigil, region: region, ..}) => {
615 let freevars = freevars::get_freevars(tcx, expr.id);
616 if freevars.is_empty() {
617 // No free variables means that the environment
618 // will be NULL at runtime and hence the closure
619 // has static lifetime.
621 // Closure must not outlive the variables it closes over.
622 constrain_free_variables(rcx, region, expr, freevars);
624 // Closure cannot outlive the appropriate temporary scope.
625 let s = rcx.repeating_scope;
626 rcx.fcx.mk_subr(true, infer::InfStackClosure(expr.span),
627 region, ty::ReScope(s));
633 let repeating_scope = rcx.set_repeating_scope(body.id);
634 visit::walk_expr(rcx, expr, ());
635 rcx.set_repeating_scope(repeating_scope);
637 match ty::get(function_type).sty {
638 ty::ty_closure(~ty::ClosureTy {sigil: ast::BorrowedSigil, ..}) => {
639 let freevars = freevars::get_freevars(tcx, expr.id);
640 propagate_upupvar_borrow_kind(rcx, expr, freevars);
645 fn constrain_free_variables(rcx: &mut Rcx,
648 freevars: freevars::freevar_info) {
650 * Make sure that all free variables referenced inside the closure
651 * outlive the closure itself. Also, create an entry in the
652 * upvar_borrows map with a region.
655 let tcx = rcx.fcx.ccx.tcx;
656 let infcx = rcx.fcx.infcx();
657 debug!("constrain_free_variables({}, {})",
658 region.repr(tcx), expr.repr(tcx));
659 for freevar in freevars.iter() {
660 debug!("freevar def is {:?}", freevar.def);
662 // Identify the variable being closed over and its node-id.
663 let def = freevar.def;
664 let def_id = ast_util::def_id_of_def(def);
665 assert!(def_id.krate == ast::LOCAL_CRATE);
666 let upvar_id = ty::UpvarId { var_id: def_id.node,
667 closure_expr_id: expr.id };
669 // Create a region variable to represent this borrow. This borrow
670 // must outlive the region on the closure.
671 let origin = infer::UpvarRegion(upvar_id, expr.span);
672 let freevar_region = infcx.next_region_var(origin);
673 rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node),
674 region, freevar_region);
676 // Create a UpvarBorrow entry. Note that we begin with a
677 // const borrow_kind, but change it to either mut or
678 // immutable as dictated by the uses.
679 let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow,
680 region: freevar_region };
681 let mut upvar_borrow_map = rcx.fcx.inh.upvar_borrow_map.borrow_mut();
682 upvar_borrow_map.get().insert(upvar_id, upvar_borrow);
684 // Guarantee that the closure does not outlive the variable itself.
685 let en_region = region_of_def(rcx.fcx, def);
686 debug!("en_region = {}", en_region.repr(tcx));
687 rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node),
692 fn propagate_upupvar_borrow_kind(rcx: &mut Rcx,
694 freevars: freevars::freevar_info) {
695 let tcx = rcx.fcx.ccx.tcx;
696 debug!("propagate_upupvar_borrow_kind({})", expr.repr(tcx));
697 for freevar in freevars.iter() {
698 // Because of the semi-hokey way that we are doing
699 // borrow_kind inference, we need to check for
700 // indirect dependencies, like so:
709 // Here, the `inner_call` is basically "reborrowing" the
710 // outer pointer. With no other changes, `inner_call`
711 // would infer that it requires a mutable borrow, but
712 // `outer_call` would infer that a const borrow is
713 // sufficient. This is because we haven't linked the
714 // borrow_kind of the borrow that occurs in the inner
715 // closure to the borrow_kind of the borrow in the outer
716 // closure. Note that regions *are* naturally linked
717 // because we have a proper inference scheme there.
719 // Anyway, for borrow_kind, we basically go back over now
720 // after checking the inner closure (and hence
721 // determining the final borrow_kind) and propagate that as
722 // a constraint on the outer closure.
724 ast::DefUpvar(var_id, _, outer_closure_id, _) => {
725 // thing being captured is itself an upvar:
726 let outer_upvar_id = ty::UpvarId {
728 closure_expr_id: outer_closure_id };
729 let inner_upvar_id = ty::UpvarId {
731 closure_expr_id: expr.id };
732 link_upvar_borrow_kind_for_nested_closures(rcx,
742 fn constrain_callee(rcx: &mut Rcx,
743 callee_id: ast::NodeId,
744 call_expr: &ast::Expr,
745 callee_expr: &ast::Expr) {
746 let call_region = ty::ReScope(call_expr.id);
748 let callee_ty = rcx.resolve_node_type(callee_id);
749 match ty::get(callee_ty).sty {
750 ty::ty_bare_fn(..) => { }
751 ty::ty_closure(ref closure_ty) => {
752 rcx.fcx.mk_subr(true, infer::InvokeClosure(callee_expr.span),
753 call_region, closure_ty.region);
756 // this should not happen, but it does if the program is
759 // tcx.sess.span_bug(
761 // format!("Calling non-function: {}", callee_ty.repr(tcx)));
766 fn constrain_call(rcx: &mut Rcx,
767 // might be expr_call, expr_method_call, or an overloaded
769 fn_expr_id: Option<ast::NodeId>,
770 call_expr: &ast::Expr,
771 receiver: Option<@ast::Expr>,
772 arg_exprs: &[@ast::Expr],
773 implicitly_ref_args: bool) {
774 //! Invoked on every call site (i.e., normal calls, method calls,
775 //! and overloaded operators). Constrains the regions which appear
776 //! in the type of the function. Also constrains the regions that
777 //! appear in the arguments appropriately.
779 let tcx = rcx.fcx.tcx();
780 debug!("constrain_call(call_expr={}, \
783 implicitly_ref_args={:?})",
787 implicitly_ref_args);
788 let callee_ty = match fn_expr_id {
789 Some(id) => rcx.resolve_node_type(id),
790 None => rcx.resolve_method_type(MethodCall::expr(call_expr.id))
791 .expect("call should have been to a method")
793 if ty::type_is_error(callee_ty) {
794 // Bail, as function type is unknown
797 let fn_sig = ty::ty_fn_sig(callee_ty);
799 // `callee_region` is the scope representing the time in which the
802 // FIXME(#6268) to support nested method calls, should be callee_id
803 let callee_scope = call_expr.id;
804 let callee_region = ty::ReScope(callee_scope);
806 for &arg_expr in arg_exprs.iter() {
809 // ensure that any regions appearing in the argument type are
810 // valid for at least the lifetime of the function:
811 constrain_regions_in_type_of_node(
812 rcx, arg_expr.id, callee_region,
813 infer::CallArg(arg_expr.span));
815 // unfortunately, there are two means of taking implicit
816 // references, and we need to propagate constraints as a
817 // result. modes are going away and the "DerefArgs" code
818 // should be ported to use adjustments
819 if implicitly_ref_args {
820 link_by_ref(rcx, arg_expr, callee_scope);
824 // as loop above, but for receiver
825 for &r in receiver.iter() {
827 constrain_regions_in_type_of_node(
828 rcx, r.id, callee_region, infer::CallRcvr(r.span));
829 if implicitly_ref_args {
830 link_by_ref(rcx, r, callee_scope);
834 // constrain regions that may appear in the return type to be
835 // valid for the function call:
836 constrain_regions_in_type(
837 rcx, callee_region, infer::CallReturn(call_expr.span),
841 fn constrain_autoderefs(rcx: &mut Rcx,
842 deref_expr: &ast::Expr,
844 mut derefd_ty: ty::t) {
846 * Invoked on any auto-dereference that occurs. Checks that if
847 * this is a region pointer being dereferenced, the lifetime of
848 * the pointer includes the deref expr.
850 let r_deref_expr = ty::ReScope(deref_expr.id);
851 for i in range(0u, derefs) {
852 debug!("constrain_autoderefs(deref_expr=?, derefd_ty={}, derefs={:?}/{:?}",
853 rcx.fcx.infcx().ty_to_str(derefd_ty),
856 let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
857 derefd_ty = match rcx.fcx.inh.method_map.get().find(&method_call) {
859 // Treat overloaded autoderefs as if an AutoRef adjustment
860 // was applied on the base type, as that is always the case.
861 let fn_sig = ty::ty_fn_sig(method.ty);
862 let self_ty = *fn_sig.inputs.get(0);
863 let (m, r) = match ty::get(self_ty).sty {
864 ty::ty_rptr(r, ref m) => (m.mutbl, r),
865 _ => rcx.tcx().sess.span_bug(deref_expr.span,
866 format!("bad overloaded deref type {}",
867 method.ty.repr(rcx.tcx())))
870 let mut mc = mc::MemCategorizationContext { typer: &mut *rcx };
871 let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
872 link_region(mc.typer, deref_expr.span, r, m, self_cmt);
875 // Specialized version of constrain_call.
876 constrain_regions_in_type(rcx, r_deref_expr,
877 infer::CallRcvr(deref_expr.span),
879 constrain_regions_in_type(rcx, r_deref_expr,
880 infer::CallReturn(deref_expr.span),
887 match ty::get(derefd_ty).sty {
888 ty::ty_rptr(r_ptr, _) => {
889 mk_subregion_due_to_dereference(rcx, deref_expr.span,
890 r_deref_expr, r_ptr);
895 match ty::deref(derefd_ty, true) {
896 Some(mt) => derefd_ty = mt.ty,
897 /* if this type can't be dereferenced, then there's already an error
898 in the session saying so. Just bail out for now */
904 pub fn mk_subregion_due_to_dereference(rcx: &mut Rcx,
906 minimum_lifetime: ty::Region,
907 maximum_lifetime: ty::Region) {
908 rcx.fcx.mk_subr(true, infer::DerefPointer(deref_span),
909 minimum_lifetime, maximum_lifetime)
913 fn constrain_index(rcx: &mut Rcx,
914 index_expr: &ast::Expr,
918 * Invoked on any index expression that occurs. Checks that if
919 * this is a slice being indexed, the lifetime of the pointer
920 * includes the deref expr.
923 debug!("constrain_index(index_expr=?, indexed_ty={}",
924 rcx.fcx.infcx().ty_to_str(indexed_ty));
926 let r_index_expr = ty::ReScope(index_expr.id);
927 match ty::get(indexed_ty).sty {
928 ty::ty_str(ty::vstore_slice(r_ptr)) |
929 ty::ty_vec(_, ty::vstore_slice(r_ptr)) => {
930 rcx.fcx.mk_subr(true, infer::IndexSlice(index_expr.span),
931 r_index_expr, r_ptr);
938 fn constrain_regions_in_type_of_node(
941 minimum_lifetime: ty::Region,
942 origin: infer::SubregionOrigin) -> bool
944 //! Guarantees that any lifetimes which appear in the type of
945 //! the node `id` (after applying adjustments) are valid for at
946 //! least `minimum_lifetime`
948 let tcx = rcx.fcx.tcx();
950 // Try to resolve the type. If we encounter an error, then typeck
951 // is going to fail anyway, so just stop here and let typeck
952 // report errors later on in the writeback phase.
953 let ty0 = rcx.resolve_node_type(id);
954 let adjustment = rcx.fcx.inh.adjustments.borrow().get().find_copy(&id);
955 let ty = ty::adjust_ty(tcx, origin.span(), id, ty0, adjustment,
956 |method_call| rcx.resolve_method_type(method_call));
957 debug!("constrain_regions_in_type_of_node(\
958 ty={}, ty0={}, id={}, minimum_lifetime={:?}, adjustment={:?})",
959 ty_to_str(tcx, ty), ty_to_str(tcx, ty0),
960 id, minimum_lifetime, adjustment);
961 constrain_regions_in_type(rcx, minimum_lifetime, origin, ty)
964 fn constrain_regions_in_type(
966 minimum_lifetime: ty::Region,
967 origin: infer::SubregionOrigin,
971 * Requires that any regions which appear in `ty` must be
972 * superregions of `minimum_lifetime`. Also enforces the constraint
973 * that given a pointer type `&'r T`, T must not contain regions
974 * that outlive 'r, as well as analogous constraints for other
977 * This check prevents regions from being used outside of the block in
978 * which they are valid. Recall that regions represent blocks of
979 * code or expressions: this requirement basically says "any place
980 * that uses or may use a region R must be within the block of
981 * code that R corresponds to."
984 let e = rcx.errors_reported;
985 let tcx = rcx.fcx.ccx.tcx;
987 debug!("constrain_regions_in_type(minimum_lifetime={}, ty={})",
988 region_to_str(tcx, "", false, minimum_lifetime),
991 relate_nested_regions(tcx, Some(minimum_lifetime), ty, |r_sub, r_sup| {
992 debug!("relate_nested_regions(r_sub={}, r_sup={})",
996 if r_sup.is_bound() || r_sub.is_bound() {
997 // a bound region is one which appears inside an fn type.
998 // (e.g., the `&` in `fn(&T)`). Such regions need not be
999 // constrained by `minimum_lifetime` as they are placeholders
1000 // for regions that are as-yet-unknown.
1001 } else if r_sub == minimum_lifetime {
1007 true, infer::ReferenceOutlivesReferent(ty, origin.span()),
1012 return e == rcx.errors_reported;
1015 fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
1016 mutability: ast::Mutability, base: &ast::Expr) {
1018 * Computes the guarantor for an expression `&base` and then
1019 * ensures that the lifetime of the resulting pointer is linked
1020 * to the lifetime of its guarantor (if any).
1023 debug!("link_addr_of(base=?)");
1026 let mut mc = mc::MemCategorizationContext { typer: &mut *rcx };
1027 ignore_err!(mc.cat_expr(base))
1029 link_region_from_node_type(rcx, expr.span, expr.id, mutability, cmt);
1032 fn link_local(rcx: &mut Rcx, local: &ast::Local) {
1034 * Computes the guarantors for any ref bindings in a `let` and
1035 * then ensures that the lifetime of the resulting pointer is
1036 * linked to the lifetime of the initialization expression.
1039 debug!("regionck::for_local()");
1040 let init_expr = match local.init {
1044 let mut mc = mc::MemCategorizationContext { typer: rcx };
1045 let discr_cmt = ignore_err!(mc.cat_expr(init_expr));
1046 link_pattern(&mut mc, discr_cmt, local.pat);
1049 fn link_match(rcx: &mut Rcx, discr: &ast::Expr, arms: &[ast::Arm]) {
1051 * Computes the guarantors for any ref bindings in a match and
1052 * then ensures that the lifetime of the resulting pointer is
1053 * linked to the lifetime of its guarantor (if any).
1056 debug!("regionck::for_match()");
1057 let mut mc = mc::MemCategorizationContext { typer: rcx };
1058 let discr_cmt = ignore_err!(mc.cat_expr(discr));
1059 debug!("discr_cmt={}", discr_cmt.repr(mc.typer.tcx()));
1060 for arm in arms.iter() {
1061 for &root_pat in arm.pats.iter() {
1062 link_pattern(&mut mc, discr_cmt, root_pat);
1067 fn link_pattern(mc: &mut mc::MemCategorizationContext<&mut Rcx>,
1069 root_pat: @ast::Pat) {
1071 * Link lifetimes of any ref bindings in `root_pat` to
1072 * the pointers found in the discriminant, if needed.
1075 let _ = mc.cat_pattern(discr_cmt, root_pat, |mc, sub_cmt, sub_pat| {
1076 match sub_pat.node {
1078 ast::PatIdent(ast::BindByRef(mutbl), _, _) => {
1079 link_region_from_node_type(
1080 mc.typer, sub_pat.span, sub_pat.id,
1084 // `[_, ..slice, _]` pattern
1085 ast::PatVec(_, Some(slice_pat), _) => {
1086 match mc.cat_slice_pattern(sub_cmt, slice_pat) {
1087 Ok((slice_cmt, slice_mutbl, slice_r)) => {
1088 link_region(mc.typer, sub_pat.span, slice_r,
1089 slice_mutbl, slice_cmt);
1099 fn link_autoref(rcx: &mut Rcx,
1102 autoref: &ty::AutoRef) {
1104 * Link lifetime of borrowed pointer resulting from autoref
1105 * to lifetimes in the value being autoref'd.
1108 debug!("link_autoref(autoref={:?})", autoref);
1109 let mut mc = mc::MemCategorizationContext { typer: rcx };
1110 let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
1111 debug!("expr_cmt={}", expr_cmt.repr(mc.typer.tcx()));
1114 ty::AutoPtr(r, m) => {
1115 link_region(mc.typer, expr.span, r, m, expr_cmt);
1118 ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => {
1119 let cmt_index = mc.cat_index(expr, expr_cmt, autoderefs+1);
1120 link_region(mc.typer, expr.span, r, m, cmt_index);
1123 ty::AutoBorrowFn(r) => {
1124 let cmt_deref = mc.cat_deref_fn_or_obj(expr, expr_cmt, 0);
1125 link_region(mc.typer, expr.span, r, ast::MutImmutable, cmt_deref);
1128 ty::AutoBorrowObj(r, m) => {
1129 let cmt_deref = mc.cat_deref_fn_or_obj(expr, expr_cmt, 0);
1130 link_region(mc.typer, expr.span, r, m, cmt_deref);
1133 ty::AutoUnsafe(_) => {}
1137 fn link_by_ref(rcx: &mut Rcx,
1139 callee_scope: ast::NodeId) {
1141 * Computes the guarantor for cases where the `expr` is
1142 * being passed by implicit reference and must outlive
1146 let tcx = rcx.tcx();
1147 debug!("link_by_ref(expr={}, callee_scope={})",
1148 expr.repr(tcx), callee_scope);
1149 let mut mc = mc::MemCategorizationContext { typer: rcx };
1150 let expr_cmt = ignore_err!(mc.cat_expr(expr));
1151 let region_min = ty::ReScope(callee_scope);
1152 link_region(mc.typer, expr.span, region_min, ast::MutImmutable, expr_cmt);
1155 fn link_region_from_node_type(rcx: &mut Rcx,
1158 mutbl: ast::Mutability,
1159 cmt_borrowed: mc::cmt) {
1161 * Like `link_region()`, except that the region is
1162 * extracted from the type of `id`, which must be some
1163 * reference (`&T`, `&str`, etc).
1166 let rptr_ty = rcx.resolve_node_type(id);
1167 if !ty::type_is_bot(rptr_ty) && !ty::type_is_error(rptr_ty) {
1168 let tcx = rcx.fcx.ccx.tcx;
1169 debug!("rptr_ty={}", ty_to_str(tcx, rptr_ty));
1170 let r = ty::ty_region(tcx, span, rptr_ty);
1171 link_region(rcx, span, r, mutbl, cmt_borrowed);
1175 fn link_region(rcx: &mut Rcx,
1177 region_min: ty::Region,
1178 mutbl: ast::Mutability,
1179 cmt_borrowed: mc::cmt) {
1181 * Informs the inference engine that a borrow of `cmt`
1182 * must have mutability `mutbl` and lifetime `region_min`.
1183 * If `cmt` is a deref of a region pointer with
1184 * lifetime `r_borrowed`, this will add the constraint that
1185 * `region_min <= r_borrowed`.
1188 // Iterate through all the things that must be live at least
1189 // for the lifetime `region_min` for the borrow to be valid:
1190 let mut cmt_borrowed = cmt_borrowed;
1192 debug!("link_region(region_min={}, mutbl={}, cmt_borrowed={})",
1193 region_min.repr(rcx.tcx()),
1194 mutbl.repr(rcx.tcx()),
1195 cmt_borrowed.repr(rcx.tcx()));
1196 match cmt_borrowed.cat {
1197 mc::cat_deref(base, _, mc::BorrowedPtr(_, r_borrowed)) => {
1198 // References to an upvar `x` are translated to
1199 // `*x`, since that is what happens in the
1200 // underlying machine. We detect such references
1201 // and treat them slightly differently, both to
1202 // offer better error messages and because we need
1203 // to infer the kind of borrow (mut, const, etc)
1204 // to use for each upvar.
1205 let cause = match base.cat {
1206 mc::cat_upvar(ref upvar_id, _) => {
1207 let mut upvar_borrow_map =
1208 rcx.fcx.inh.upvar_borrow_map.borrow_mut();
1209 match upvar_borrow_map.get().find_mut(upvar_id) {
1210 Some(upvar_borrow) => {
1211 debug!("link_region: {} <= {}",
1212 region_min.repr(rcx.tcx()),
1213 upvar_borrow.region.repr(rcx.tcx()));
1214 adjust_upvar_borrow_kind_for_loan(
1218 infer::ReborrowUpvar(span, *upvar_id)
1221 rcx.tcx().sess.span_bug(
1223 format!("Illegal upvar id: {}",
1224 upvar_id.repr(rcx.tcx())));
1230 infer::Reborrow(span)
1234 debug!("link_region: {} <= {}",
1235 region_min.repr(rcx.tcx()),
1236 r_borrowed.repr(rcx.tcx()));
1237 rcx.fcx.mk_subr(true, cause, region_min, r_borrowed);
1239 if mutbl == ast::MutMutable {
1240 // If this is a mutable borrow, then the thing
1241 // being borrowed will have to be unique.
1242 // In user code, this means it must be an `&mut`
1243 // borrow, but for an upvar, we might opt
1244 // for an immutable-unique borrow.
1245 adjust_upvar_borrow_kind_for_unique(rcx, base);
1248 // Borrowing an `&mut` pointee for `region_min` is
1249 // only valid if the pointer resides in a unique
1250 // location which is itself valid for
1251 // `region_min`. We don't care about the unique
1252 // part, but we may need to influence the
1253 // inference to ensure that the location remains
1256 // FIXME(#8624) fixing borrowck will require this
1257 // if m == ast::m_mutbl {
1258 // cmt_borrowed = cmt_base;
1264 mc::cat_discr(cmt_base, _) |
1265 mc::cat_downcast(cmt_base) |
1266 mc::cat_deref(cmt_base, _, mc::OwnedPtr) |
1267 mc::cat_interior(cmt_base, _) => {
1268 // Interior or owned data requires its base to be valid
1269 cmt_borrowed = cmt_base;
1271 mc::cat_deref(_, _, mc::GcPtr(..)) |
1272 mc::cat_deref(_, _, mc::UnsafePtr(..)) |
1273 mc::cat_static_item |
1274 mc::cat_copied_upvar(..) |
1278 mc::cat_rvalue(..) => {
1279 // These are all "base cases" with independent lifetimes
1280 // that are not subject to inference
1287 fn adjust_borrow_kind_for_assignment_lhs(rcx: &mut Rcx,
1290 * Adjusts the inferred borrow_kind as needed to account
1291 * for upvars that are assigned to in an assignment
1295 let mut mc = mc::MemCategorizationContext { typer: rcx };
1296 let cmt = ignore_err!(mc.cat_expr(lhs));
1297 adjust_upvar_borrow_kind_for_mut(mc.typer, cmt);
1300 fn adjust_upvar_borrow_kind_for_mut(rcx: &mut Rcx,
1304 debug!("adjust_upvar_borrow_kind_for_mut(cmt={})",
1305 cmt.repr(rcx.tcx()));
1308 mc::cat_deref(base, _, mc::OwnedPtr) |
1309 mc::cat_interior(base, _) |
1310 mc::cat_downcast(base) |
1311 mc::cat_discr(base, _) => {
1312 // Interior or owned data is mutable if base is
1313 // mutable, so iterate to the base.
1318 mc::cat_deref(base, _, mc::BorrowedPtr(..)) => {
1320 mc::cat_upvar(ref upvar_id, _) => {
1321 // if this is an implicit deref of an
1322 // upvar, then we need to modify the
1323 // borrow_kind of the upvar to make sure it
1324 // is inferred to mutable if necessary
1325 let mut upvar_borrow_map =
1326 rcx.fcx.inh.upvar_borrow_map.borrow_mut();
1327 let ub = upvar_borrow_map.get().get_mut(upvar_id);
1328 return adjust_upvar_borrow_kind(*upvar_id, ub, ty::MutBorrow);
1332 // assignment to deref of an `&mut`
1333 // borrowed pointer implies that the
1334 // pointer itself must be unique, but not
1335 // necessarily *mutable*
1336 return adjust_upvar_borrow_kind_for_unique(rcx, base);
1341 mc::cat_deref(_, _, mc::UnsafePtr(..)) |
1342 mc::cat_deref(_, _, mc::GcPtr) |
1343 mc::cat_static_item |
1345 mc::cat_copied_upvar(_) |
1348 mc::cat_upvar(..) => {
1355 fn adjust_upvar_borrow_kind_for_unique(rcx: &mut Rcx,
1359 debug!("adjust_upvar_borrow_kind_for_unique(cmt={})",
1360 cmt.repr(rcx.tcx()));
1363 mc::cat_deref(base, _, mc::OwnedPtr) |
1364 mc::cat_interior(base, _) |
1365 mc::cat_downcast(base) |
1366 mc::cat_discr(base, _) => {
1367 // Interior or owned data is unique if base is
1373 mc::cat_deref(base, _, mc::BorrowedPtr(..)) => {
1375 mc::cat_upvar(ref upvar_id, _) => {
1376 // if this is an implicit deref of an
1377 // upvar, then we need to modify the
1378 // borrow_kind of the upvar to make sure it
1379 // is inferred to unique if necessary
1380 let mut upvar_borrow_map =
1381 rcx.fcx.inh.upvar_borrow_map.borrow_mut();
1382 let ub = upvar_borrow_map.get().get_mut(upvar_id);
1383 return adjust_upvar_borrow_kind(*upvar_id, ub, ty::UniqueImmBorrow);
1387 // for a borrowed pointer to be unique, its
1388 // base must be unique
1389 return adjust_upvar_borrow_kind_for_unique(rcx, base);
1394 mc::cat_deref(_, _, mc::UnsafePtr(..)) |
1395 mc::cat_deref(_, _, mc::GcPtr) |
1396 mc::cat_static_item |
1398 mc::cat_copied_upvar(_) |
1401 mc::cat_upvar(..) => {
1408 fn link_upvar_borrow_kind_for_nested_closures(rcx: &mut Rcx,
1409 inner_upvar_id: ty::UpvarId,
1410 outer_upvar_id: ty::UpvarId) {
1412 * Indicates that the borrow_kind of `outer_upvar_id` must
1413 * permit a reborrowing with the borrow_kind of `inner_upvar_id`.
1414 * This occurs in nested closures, see comment above at the call to
1418 debug!("link_upvar_borrow_kind: inner_upvar_id={:?} outer_upvar_id={:?}",
1419 inner_upvar_id, outer_upvar_id);
1421 let mut upvar_borrow_map = rcx.fcx.inh.upvar_borrow_map.borrow_mut();
1422 let inner_borrow = upvar_borrow_map.get().get_copy(&inner_upvar_id);
1423 match upvar_borrow_map.get().find_mut(&outer_upvar_id) {
1424 Some(outer_borrow) => {
1425 adjust_upvar_borrow_kind(outer_upvar_id, outer_borrow, inner_borrow.kind);
1427 None => { /* outer closure is not a stack closure */ }
1431 fn adjust_upvar_borrow_kind_for_loan(upvar_id: ty::UpvarId,
1432 upvar_borrow: &mut ty::UpvarBorrow,
1433 mutbl: ast::Mutability) {
1434 debug!("adjust_upvar_borrow_kind_for_loan: upvar_id={:?} kind={:?} -> {:?}",
1435 upvar_id, upvar_borrow.kind, mutbl);
1437 adjust_upvar_borrow_kind(upvar_id, upvar_borrow,
1438 ty::BorrowKind::from_mutbl(mutbl))
1441 fn adjust_upvar_borrow_kind(upvar_id: ty::UpvarId,
1442 upvar_borrow: &mut ty::UpvarBorrow,
1443 kind: ty::BorrowKind) {
1445 * We infer the borrow_kind with which to borrow upvars in a stack
1446 * closure. The borrow_kind basically follows a lattice of
1447 * `imm < unique-imm < mut`, moving from left to right as needed (but never
1448 * right to left). Here the argument `mutbl` is the borrow_kind that
1449 * is required by some particular use.
1452 debug!("adjust_upvar_borrow_kind: id={:?} kind=({:?} -> {:?})",
1453 upvar_id, upvar_borrow.kind, kind);
1455 match (upvar_borrow.kind, kind) {
1457 (ty::ImmBorrow, ty::UniqueImmBorrow) |
1458 (ty::ImmBorrow, ty::MutBorrow) |
1459 (ty::UniqueImmBorrow, ty::MutBorrow) => {
1460 upvar_borrow.kind = kind;
1463 (ty::ImmBorrow, ty::ImmBorrow) |
1464 (ty::UniqueImmBorrow, ty::ImmBorrow) |
1465 (ty::UniqueImmBorrow, ty::UniqueImmBorrow) |
1466 (ty::MutBorrow, _) => {