]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/typeck/check/regionck.rs
auto merge of #13704 : edwardw/rust/doc-hidden, r=alexcrichton
[rust.git] / src / librustc / middle / typeck / check / regionck.rs
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.
4 //
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.
10
11 /*!
12
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
19 been inferred.
20
21 ### Interaction with the borrow checker
22
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
35 checks and effort.
36
37 ### Inferring the duration of borrows, automatic and otherwise
38
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).
45
46 #### Reborrows
47
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).
60
61 There are a number of troublesome scenarios in the tests
62 `region-dependent-*.rs`, but here is one example:
63
64     struct Foo { i: int }
65     struct Bar { foo: Foo  }
66     fn get_i(x: &'a Bar) -> &'a int {
67        let foo = &x.foo; // Lifetime L1
68        &foo.i            // Lifetime L2
69     }
70
71 Note that this comes up either with `&` expressions, `ref`
72 bindings, and `autorefs`, which are the three ways to introduce
73 a borrow.
74
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
85 contents.
86
87 ### Inferring borrow kinds for upvars
88
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:
94
95     ty::ImmBorrow -> ty::UniqueImmBorrow -> ty::MutBorrow
96
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
104 from there).
105
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.)
118
119 */
120
121
122 use middle::freevars;
123 use mc = middle::mem_categorization;
124 use middle::ty::{ReScope};
125 use middle::ty;
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::nodemap::NodeMap;
135 use util::ppaux::{ty_to_str, region_to_str, Repr};
136
137 use syntax::ast::{DefArg, DefBinding, DefLocal, DefUpvar};
138 use syntax::ast;
139 use syntax::ast_util;
140 use syntax::codemap::Span;
141 use syntax::visit;
142 use syntax::visit::Visitor;
143
144 use std::cell::RefCell;
145
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(
151     ($inp: expr) => (
152         match $inp {
153             Ok(v) => v,
154             Err(()) => return
155         }
156     )
157 )
158
159 pub struct Rcx<'a> {
160     fcx: &'a FnCtxt<'a>,
161
162     // id of innermost fn or loop
163     repeating_scope: ast::NodeId,
164 }
165
166 fn region_of_def(fcx: &FnCtxt, def: ast::Def) -> ty::Region {
167     /*!
168      * Returns the validity region of `def` -- that is, how long
169      * is `def` valid?
170      */
171
172     let tcx = fcx.tcx();
173     match def {
174         DefLocal(node_id, _) | DefArg(node_id, _) |
175         DefBinding(node_id, _) => {
176             tcx.region_maps.var_region(node_id)
177         }
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)
182             }
183         }
184         _ => {
185             tcx.sess.bug(format!("unexpected def in region_of_def: {:?}",
186                               def))
187         }
188     }
189 }
190
191 impl<'a> Rcx<'a> {
192     pub fn tcx(&self) -> &'a ty::ctxt {
193         self.fcx.ccx.tcx
194     }
195
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;
199         old_scope
200     }
201
202     pub fn resolve_type(&self, unresolved_ty: ty::t) -> ty::t {
203         /*!
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.
208          *
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.
213          *
214          * Consider this silly example:
215          *
216          *     fn borrow(x: &int) -> &int {x}
217          *     fn foo(x: @int) -> int {  // block: B
218          *         let b = borrow(x);    // region: <R0>
219          *         *b
220          *     }
221          *
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.
230          */
231         match resolve_type(self.fcx.infcx(), unresolved_ty,
232                            resolve_and_force_all_but_regions) {
233             Ok(t) => t,
234             Err(_) => ty::mk_err()
235         }
236     }
237
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);
241         self.resolve_type(t)
242     }
243
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))
248     }
249
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) {
254             ty_unadjusted
255         } else {
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))
260         }
261     }
262 }
263
264 impl<'a, 'b> mc::Typer for &'a Rcx<'b> {
265     fn tcx<'a>(&'a self) -> &'a ty::ctxt {
266         self.fcx.tcx()
267     }
268
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)}
272     }
273
274     fn node_method_ty(&self, method_call: MethodCall) -> Option<ty::t> {
275         self.resolve_method_type(method_call)
276     }
277
278     fn adjustments<'a>(&'a self) -> &'a RefCell<NodeMap<ty::AutoAdjustment>> {
279         &self.fcx.inh.adjustments
280     }
281
282     fn is_method_call(&self, id: ast::NodeId) -> bool {
283         self.fcx.inh.method_map.borrow().contains_key(&MethodCall::expr(id))
284     }
285
286     fn temporary_scope(&self, id: ast::NodeId) -> Option<ast::NodeId> {
287         self.tcx().region_maps.temporary_scope(id)
288     }
289
290     fn upvar_borrow(&self, id: ty::UpvarId) -> ty::UpvarBorrow {
291         self.fcx.inh.upvar_borrow_map.borrow().get_copy(&id)
292     }
293 }
294
295 pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) {
296     let mut rcx = Rcx { fcx: fcx, repeating_scope: e.id };
297     let rcx = &mut rcx;
298     if fcx.err_count_since_creation() == 0 {
299         // regionck assumes typeck succeeded
300         rcx.visit_expr(e, ());
301     }
302     fcx.infcx().resolve_regions();
303 }
304
305 pub fn regionck_fn(fcx: &FnCtxt, blk: &ast::Block) {
306     let mut rcx = Rcx { fcx: fcx, repeating_scope: blk.id };
307     let rcx = &mut rcx;
308     if fcx.err_count_since_creation() == 0 {
309         // regionck assumes typeck succeeded
310         rcx.visit_block(blk, ());
311     }
312     fcx.infcx().resolve_regions();
313 }
314
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.
323
324     fn visit_item(&mut self, i: &ast::Item, _: ()) { visit_item(self, i); }
325
326     fn visit_expr(&mut self, ex: &ast::Expr, _: ()) { visit_expr(self, ex); }
327
328     //visit_pat: visit_pat, // (..) see above
329
330     fn visit_arm(&mut self, a: &ast::Arm, _: ()) { visit_arm(self, a); }
331
332     fn visit_local(&mut self, l: &ast::Local, _: ()) { visit_local(self, l); }
333
334     fn visit_block(&mut self, b: &ast::Block, _: ()) { visit_block(self, b); }
335 }
336
337 fn visit_item(_rcx: &mut Rcx, _item: &ast::Item) {
338     // Ignore items
339 }
340
341 fn visit_block(rcx: &mut Rcx, b: &ast::Block) {
342     visit::walk_block(rcx, b, ());
343 }
344
345 fn visit_arm(rcx: &mut Rcx, arm: &ast::Arm) {
346     // see above
347     for &p in arm.pats.iter() {
348         constrain_bindings_in_pat(p, rcx);
349     }
350
351     visit::walk_arm(rcx, arm, ());
352 }
353
354 fn visit_local(rcx: &mut Rcx, l: &ast::Local) {
355     // see above
356     constrain_bindings_in_pat(l.pat, rcx);
357     link_local(rcx, l);
358     visit::walk_local(rcx, l, ());
359 }
360
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:
368         //
369         //     // from src/test/compile-fail/borrowck-lend-flow.rs
370         //     let mut v = ~3, w = ~4;
371         //     let mut x = &mut w;
372         //     loop {
373         //         **x += 1;   // (2)
374         //         borrow(v);  //~ ERROR cannot borrow
375         //         x = &mut v; // (1)
376         //     }
377         //
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.
387
388         let var_region = tcx.region_maps.var_region(id);
389         constrain_regions_in_type_of_node(
390             rcx, id, var_region,
391             infer::BindingTypeIsNotValidAtDecl(span));
392     })
393 }
394
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);
398
399     let method_call = MethodCall::expr(expr.id);
400     let has_method_map = rcx.fcx.inh.method_map.borrow().contains_key(&method_call);
401
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);
405         match *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);
411
412                     // Require that the resulting region encompasses
413                     // the current node.
414                     //
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));
419                 }
420             }
421             ty::AutoObject(ty::RegionTraitStore(trait_region, _), _, _, _) => {
422                 // Determine if we are casting `expr` to an trait
423                 // instance.  If so, we have to be sure that the type of
424                 // the source obeys the trait's region bound.
425                 //
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.
435
436                 let source_ty = rcx.fcx.expr_ty(expr);
437                 constrain_regions_in_type(rcx, trait_region,
438                                             infer::RelateObjectBound(expr.span), source_ty);
439             }
440             _ => {}
441         }
442     }
443
444     match expr.node {
445         ast::ExprCall(callee, ref args) => {
446             constrain_callee(rcx, callee.id, expr, callee);
447             constrain_call(rcx,
448                            Some(callee.id),
449                            expr,
450                            None,
451                            args.as_slice(),
452                            false);
453
454             visit::walk_expr(rcx, expr, ());
455         }
456
457         ast::ExprMethodCall(_, _, ref args) => {
458             constrain_call(rcx, None, expr, Some(*args.get(0)),
459                            args.slice_from(1), false);
460
461             visit::walk_expr(rcx, expr, ());
462         }
463
464         ast::ExprAssign(lhs, _) => {
465             adjust_borrow_kind_for_assignment_lhs(rcx, lhs);
466             visit::walk_expr(rcx, expr, ());
467         }
468
469         ast::ExprAssignOp(_, lhs, rhs) => {
470             if has_method_map {
471                 constrain_call(rcx, None, expr, Some(lhs), [rhs], true);
472             }
473
474             adjust_borrow_kind_for_assignment_lhs(rcx, lhs);
475
476             visit::walk_expr(rcx, expr, ());
477         }
478
479         ast::ExprIndex(lhs, rhs) |
480         ast::ExprBinary(_, lhs, rhs) if has_method_map => {
481             // As `expr_method_call`, but the call is via an
482             // overloaded op.  Note that we (sadly) currently use an
483             // implicit "by ref" sort of passing style here.  This
484             // should be converted to an adjustment!
485             constrain_call(rcx, None, expr, Some(lhs), [rhs], true);
486
487             visit::walk_expr(rcx, expr, ());
488         }
489
490         ast::ExprUnary(_, lhs) if has_method_map => {
491             // As above.
492             constrain_call(rcx, None, expr, Some(lhs), [], true);
493
494             visit::walk_expr(rcx, expr, ());
495         }
496
497         ast::ExprUnary(ast::UnDeref, base) => {
498             // For *a, the lifetime of a must enclose the deref
499             let method_call = MethodCall::expr(expr.id);
500             let base_ty = match rcx.fcx.inh.method_map.borrow().find(&method_call) {
501                 Some(method) => {
502                     constrain_call(rcx, None, expr, Some(base), [], true);
503                     ty::ty_fn_ret(method.ty)
504                 }
505                 None => rcx.resolve_node_type(base.id)
506             };
507             match ty::get(base_ty).sty {
508                 ty::ty_rptr(r_ptr, _) => {
509                     mk_subregion_due_to_dereference(rcx, expr.span,
510                                                     ty::ReScope(expr.id), r_ptr);
511                 }
512                 _ => {}
513             }
514
515             visit::walk_expr(rcx, expr, ());
516         }
517
518         ast::ExprIndex(vec_expr, _) => {
519             // For a[b], the lifetime of a must enclose the deref
520             let vec_type = rcx.resolve_expr_type_adjusted(vec_expr);
521             constrain_index(rcx, expr, vec_type);
522
523             visit::walk_expr(rcx, expr, ());
524         }
525
526         ast::ExprCast(source, _) => {
527             // Determine if we are casting `source` to an trait
528             // instance.  If so, we have to be sure that the type of
529             // the source obeys the trait's region bound.
530             //
531             // Note: there is a subtle point here concerning type
532             // parameters.  It is possible that the type of `source`
533             // contains type parameters, which in turn may contain
534             // regions that are not visible to us (only the caller
535             // knows about them).  The kind checker is ultimately
536             // responsible for guaranteeing region safety in that
537             // particular case.  There is an extensive comment on the
538             // function check_cast_for_escaping_regions() in kind.rs
539             // explaining how it goes about doing that.
540             let target_ty = rcx.resolve_node_type(expr.id);
541             match ty::get(target_ty).sty {
542                 ty::ty_trait(~ty::TyTrait {
543                     store: ty::RegionTraitStore(trait_region, _), ..
544                 }) => {
545                     let source_ty = rcx.resolve_expr_type_adjusted(source);
546                     constrain_regions_in_type(
547                         rcx,
548                         trait_region,
549                         infer::RelateObjectBound(expr.span),
550                         source_ty);
551                 }
552                 _ => ()
553             }
554
555             visit::walk_expr(rcx, expr, ());
556         }
557
558         ast::ExprAddrOf(m, base) => {
559             link_addr_of(rcx, expr, m, base);
560
561             // Require that when you write a `&expr` expression, the
562             // resulting pointer has a lifetime that encompasses the
563             // `&expr` expression itself. Note that we constraining
564             // the type of the node expr.id here *before applying
565             // adjustments*.
566             //
567             // FIXME(#6268) nested method calls requires that this rule change
568             let ty0 = rcx.resolve_node_type(expr.id);
569             constrain_regions_in_type(rcx, ty::ReScope(expr.id),
570                                       infer::AddrOf(expr.span), ty0);
571             visit::walk_expr(rcx, expr, ());
572         }
573
574         ast::ExprMatch(discr, ref arms) => {
575             link_match(rcx, discr, arms.as_slice());
576
577             visit::walk_expr(rcx, expr, ());
578         }
579
580         ast::ExprFnBlock(_, ref body) | ast::ExprProc(_, ref body) => {
581             check_expr_fn_block(rcx, expr, &**body);
582         }
583
584         ast::ExprLoop(body, _) => {
585             let repeating_scope = rcx.set_repeating_scope(body.id);
586             visit::walk_expr(rcx, expr, ());
587             rcx.set_repeating_scope(repeating_scope);
588         }
589
590         ast::ExprWhile(cond, body) => {
591             let repeating_scope = rcx.set_repeating_scope(cond.id);
592             rcx.visit_expr(cond, ());
593
594             rcx.set_repeating_scope(body.id);
595             rcx.visit_block(body, ());
596
597             rcx.set_repeating_scope(repeating_scope);
598         }
599
600         _ => {
601             visit::walk_expr(rcx, expr, ());
602         }
603     }
604 }
605
606 fn check_expr_fn_block(rcx: &mut Rcx,
607                        expr: &ast::Expr,
608                        body: &ast::Block) {
609     let tcx = rcx.fcx.tcx();
610     let function_type = rcx.resolve_node_type(expr.id);
611     match ty::get(function_type).sty {
612         ty::ty_closure(~ty::ClosureTy {
613                 store: ty::RegionTraitStore(region, _), ..}) => {
614             freevars::with_freevars(tcx, expr.id, |freevars| {
615                 if freevars.is_empty() {
616                     // No free variables means that the environment
617                     // will be NULL at runtime and hence the closure
618                     // has static lifetime.
619                 } else {
620                     // Closure must not outlive the variables it closes over.
621                     constrain_free_variables(rcx, region, expr, freevars);
622
623                     // Closure cannot outlive the appropriate temporary scope.
624                     let s = rcx.repeating_scope;
625                     rcx.fcx.mk_subr(true, infer::InfStackClosure(expr.span),
626                                     region, ty::ReScope(s));
627                 }
628             });
629         }
630         _ => ()
631     }
632
633     let repeating_scope = rcx.set_repeating_scope(body.id);
634     visit::walk_expr(rcx, expr, ());
635     rcx.set_repeating_scope(repeating_scope);
636
637     match ty::get(function_type).sty {
638         ty::ty_closure(~ty::ClosureTy {store: ty::RegionTraitStore(..), ..}) => {
639             freevars::with_freevars(tcx, expr.id, |freevars| {
640                 propagate_upupvar_borrow_kind(rcx, expr, freevars);
641             });
642         }
643         _ => ()
644     }
645
646     fn constrain_free_variables(rcx: &mut Rcx,
647                                 region: ty::Region,
648                                 expr: &ast::Expr,
649                                 freevars: &[freevars::freevar_entry]) {
650         /*!
651          * Make sure that all free variables referenced inside the closure
652          * outlive the closure itself. Also, create an entry in the
653          * upvar_borrows map with a region.
654          */
655
656         let tcx = rcx.fcx.ccx.tcx;
657         let infcx = rcx.fcx.infcx();
658         debug!("constrain_free_variables({}, {})",
659                region.repr(tcx), expr.repr(tcx));
660         for freevar in freevars.iter() {
661             debug!("freevar def is {:?}", freevar.def);
662
663             // Identify the variable being closed over and its node-id.
664             let def = freevar.def;
665             let def_id = ast_util::def_id_of_def(def);
666             assert!(def_id.krate == ast::LOCAL_CRATE);
667             let upvar_id = ty::UpvarId { var_id: def_id.node,
668                                          closure_expr_id: expr.id };
669
670             // Create a region variable to represent this borrow. This borrow
671             // must outlive the region on the closure.
672             let origin = infer::UpvarRegion(upvar_id, expr.span);
673             let freevar_region = infcx.next_region_var(origin);
674             rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node),
675                             region, freevar_region);
676
677             // Create a UpvarBorrow entry. Note that we begin with a
678             // const borrow_kind, but change it to either mut or
679             // immutable as dictated by the uses.
680             let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow,
681                                                  region: freevar_region };
682             rcx.fcx.inh.upvar_borrow_map.borrow_mut().insert(upvar_id,
683                                                              upvar_borrow);
684
685             // Guarantee that the closure does not outlive the variable itself.
686             let en_region = region_of_def(rcx.fcx, def);
687             debug!("en_region = {}", en_region.repr(tcx));
688             rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node),
689                             region, en_region);
690         }
691     }
692
693     fn propagate_upupvar_borrow_kind(rcx: &mut Rcx,
694                                      expr: &ast::Expr,
695                                      freevars: &[freevars::freevar_entry]) {
696         let tcx = rcx.fcx.ccx.tcx;
697         debug!("propagate_upupvar_borrow_kind({})", expr.repr(tcx));
698         for freevar in freevars.iter() {
699             // Because of the semi-hokey way that we are doing
700             // borrow_kind inference, we need to check for
701             // indirect dependencies, like so:
702             //
703             //     let mut x = 0;
704             //     outer_call(|| {
705             //         inner_call(|| {
706             //             x = 1;
707             //         });
708             //     });
709             //
710             // Here, the `inner_call` is basically "reborrowing" the
711             // outer pointer. With no other changes, `inner_call`
712             // would infer that it requires a mutable borrow, but
713             // `outer_call` would infer that a const borrow is
714             // sufficient. This is because we haven't linked the
715             // borrow_kind of the borrow that occurs in the inner
716             // closure to the borrow_kind of the borrow in the outer
717             // closure. Note that regions *are* naturally linked
718             // because we have a proper inference scheme there.
719             //
720             // Anyway, for borrow_kind, we basically go back over now
721             // after checking the inner closure (and hence
722             // determining the final borrow_kind) and propagate that as
723             // a constraint on the outer closure.
724             match freevar.def {
725                 ast::DefUpvar(var_id, _, outer_closure_id, _) => {
726                     // thing being captured is itself an upvar:
727                     let outer_upvar_id = ty::UpvarId {
728                         var_id: var_id,
729                         closure_expr_id: outer_closure_id };
730                     let inner_upvar_id = ty::UpvarId {
731                         var_id: var_id,
732                         closure_expr_id: expr.id };
733                     link_upvar_borrow_kind_for_nested_closures(rcx,
734                                                                inner_upvar_id,
735                                                                outer_upvar_id);
736                 }
737                 _ => {}
738             }
739         }
740     }
741 }
742
743 fn constrain_callee(rcx: &mut Rcx,
744                     callee_id: ast::NodeId,
745                     call_expr: &ast::Expr,
746                     callee_expr: &ast::Expr) {
747     let call_region = ty::ReScope(call_expr.id);
748
749     let callee_ty = rcx.resolve_node_type(callee_id);
750     match ty::get(callee_ty).sty {
751         ty::ty_bare_fn(..) => { }
752         ty::ty_closure(ref closure_ty) => {
753             let region = match closure_ty.store {
754                 ty::RegionTraitStore(r, _) => {
755                     // While we're here, link the closure's region with a unique
756                     // immutable borrow (gathered later in borrowck)
757                     let mc = mc::MemCategorizationContext { typer: &*rcx };
758                     let expr_cmt = ignore_err!(mc.cat_expr(callee_expr));
759                     link_region(mc.typer, callee_expr.span, call_region,
760                                 ty::UniqueImmBorrow, expr_cmt);
761                     r
762                 }
763                 ty::UniqTraitStore => ty::ReStatic
764             };
765             rcx.fcx.mk_subr(true, infer::InvokeClosure(callee_expr.span),
766                             call_region, region);
767         }
768         _ => {
769             // this should not happen, but it does if the program is
770             // erroneous
771             //
772             // tcx.sess.span_bug(
773             //     callee_expr.span,
774             //     format!("Calling non-function: {}", callee_ty.repr(tcx)));
775         }
776     }
777 }
778
779 fn constrain_call(rcx: &mut Rcx,
780                   // might be expr_call, expr_method_call, or an overloaded
781                   // operator
782                   fn_expr_id: Option<ast::NodeId>,
783                   call_expr: &ast::Expr,
784                   receiver: Option<@ast::Expr>,
785                   arg_exprs: &[@ast::Expr],
786                   implicitly_ref_args: bool) {
787     //! Invoked on every call site (i.e., normal calls, method calls,
788     //! and overloaded operators). Constrains the regions which appear
789     //! in the type of the function. Also constrains the regions that
790     //! appear in the arguments appropriately.
791
792     let tcx = rcx.fcx.tcx();
793     debug!("constrain_call(call_expr={}, \
794             receiver={}, \
795             arg_exprs={}, \
796             implicitly_ref_args={:?})",
797             call_expr.repr(tcx),
798             receiver.repr(tcx),
799             arg_exprs.repr(tcx),
800             implicitly_ref_args);
801     let callee_ty = match fn_expr_id {
802         Some(id) => rcx.resolve_node_type(id),
803         None => rcx.resolve_method_type(MethodCall::expr(call_expr.id))
804                    .expect("call should have been to a method")
805     };
806     if ty::type_is_error(callee_ty) {
807         // Bail, as function type is unknown
808         return;
809     }
810     let fn_sig = ty::ty_fn_sig(callee_ty);
811
812     // `callee_region` is the scope representing the time in which the
813     // call occurs.
814     //
815     // FIXME(#6268) to support nested method calls, should be callee_id
816     let callee_scope = call_expr.id;
817     let callee_region = ty::ReScope(callee_scope);
818
819     for &arg_expr in arg_exprs.iter() {
820         debug!("Argument");
821
822         // ensure that any regions appearing in the argument type are
823         // valid for at least the lifetime of the function:
824         constrain_regions_in_type_of_node(
825             rcx, arg_expr.id, callee_region,
826             infer::CallArg(arg_expr.span));
827
828         // unfortunately, there are two means of taking implicit
829         // references, and we need to propagate constraints as a
830         // result. modes are going away and the "DerefArgs" code
831         // should be ported to use adjustments
832         if implicitly_ref_args {
833             link_by_ref(rcx, arg_expr, callee_scope);
834         }
835     }
836
837     // as loop above, but for receiver
838     for &r in receiver.iter() {
839         debug!("Receiver");
840         constrain_regions_in_type_of_node(
841             rcx, r.id, callee_region, infer::CallRcvr(r.span));
842         if implicitly_ref_args {
843             link_by_ref(rcx, r, callee_scope);
844         }
845     }
846
847     // constrain regions that may appear in the return type to be
848     // valid for the function call:
849     constrain_regions_in_type(
850         rcx, callee_region, infer::CallReturn(call_expr.span),
851         fn_sig.output);
852 }
853
854 fn constrain_autoderefs(rcx: &mut Rcx,
855                         deref_expr: &ast::Expr,
856                         derefs: uint,
857                         mut derefd_ty: ty::t) {
858     /*!
859      * Invoked on any auto-dereference that occurs.  Checks that if
860      * this is a region pointer being dereferenced, the lifetime of
861      * the pointer includes the deref expr.
862      */
863     let r_deref_expr = ty::ReScope(deref_expr.id);
864     for i in range(0u, derefs) {
865         debug!("constrain_autoderefs(deref_expr=?, derefd_ty={}, derefs={:?}/{:?}",
866                rcx.fcx.infcx().ty_to_str(derefd_ty),
867                i, derefs);
868
869         let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
870         derefd_ty = match rcx.fcx.inh.method_map.borrow().find(&method_call) {
871             Some(method) => {
872                 // Treat overloaded autoderefs as if an AutoRef adjustment
873                 // was applied on the base type, as that is always the case.
874                 let fn_sig = ty::ty_fn_sig(method.ty);
875                 let self_ty = *fn_sig.inputs.get(0);
876                 let (m, r) = match ty::get(self_ty).sty {
877                     ty::ty_rptr(r, ref m) => (m.mutbl, r),
878                     _ => rcx.tcx().sess.span_bug(deref_expr.span,
879                             format!("bad overloaded deref type {}",
880                                 method.ty.repr(rcx.tcx())))
881                 };
882                 {
883                     let mc = mc::MemCategorizationContext { typer: &*rcx };
884                     let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
885                     link_region(mc.typer, deref_expr.span, r,
886                                 ty::BorrowKind::from_mutbl(m), self_cmt);
887                 }
888
889                 // Specialized version of constrain_call.
890                 constrain_regions_in_type(rcx, r_deref_expr,
891                                           infer::CallRcvr(deref_expr.span),
892                                           self_ty);
893                 constrain_regions_in_type(rcx, r_deref_expr,
894                                           infer::CallReturn(deref_expr.span),
895                                           fn_sig.output);
896                 fn_sig.output
897             }
898             None => derefd_ty
899         };
900
901         match ty::get(derefd_ty).sty {
902             ty::ty_rptr(r_ptr, _) => {
903                 mk_subregion_due_to_dereference(rcx, deref_expr.span,
904                                                 r_deref_expr, r_ptr);
905             }
906             _ => {}
907         }
908
909         match ty::deref(derefd_ty, true) {
910             Some(mt) => derefd_ty = mt.ty,
911             /* if this type can't be dereferenced, then there's already an error
912                in the session saying so. Just bail out for now */
913             None => break
914         }
915     }
916 }
917
918 pub fn mk_subregion_due_to_dereference(rcx: &mut Rcx,
919                                        deref_span: Span,
920                                        minimum_lifetime: ty::Region,
921                                        maximum_lifetime: ty::Region) {
922     rcx.fcx.mk_subr(true, infer::DerefPointer(deref_span),
923                     minimum_lifetime, maximum_lifetime)
924 }
925
926
927 fn constrain_index(rcx: &mut Rcx,
928                    index_expr: &ast::Expr,
929                    indexed_ty: ty::t)
930 {
931     /*!
932      * Invoked on any index expression that occurs.  Checks that if
933      * this is a slice being indexed, the lifetime of the pointer
934      * includes the deref expr.
935      */
936
937     debug!("constrain_index(index_expr=?, indexed_ty={}",
938            rcx.fcx.infcx().ty_to_str(indexed_ty));
939
940     let r_index_expr = ty::ReScope(index_expr.id);
941     match ty::get(indexed_ty).sty {
942         ty::ty_str(ty::VstoreSlice(r_ptr)) => {
943             rcx.fcx.mk_subr(true, infer::IndexSlice(index_expr.span),
944                             r_index_expr, r_ptr);
945         }
946         ty::ty_rptr(r_ptr, mt) => match ty::get(mt.ty).sty {
947             ty::ty_vec(_, None) => {
948                 rcx.fcx.mk_subr(true, infer::IndexSlice(index_expr.span),
949                                 r_index_expr, r_ptr);
950             }
951             _ => {}
952         },
953
954         _ => {}
955     }
956 }
957
958 fn constrain_regions_in_type_of_node(
959     rcx: &mut Rcx,
960     id: ast::NodeId,
961     minimum_lifetime: ty::Region,
962     origin: infer::SubregionOrigin) {
963     //! Guarantees that any lifetimes which appear in the type of
964     //! the node `id` (after applying adjustments) are valid for at
965     //! least `minimum_lifetime`
966
967     let tcx = rcx.fcx.tcx();
968
969     // Try to resolve the type.  If we encounter an error, then typeck
970     // is going to fail anyway, so just stop here and let typeck
971     // report errors later on in the writeback phase.
972     let ty0 = rcx.resolve_node_type(id);
973     let ty = ty::adjust_ty(tcx, origin.span(), id, ty0,
974                            rcx.fcx.inh.adjustments.borrow().find(&id),
975                            |method_call| rcx.resolve_method_type(method_call));
976     debug!("constrain_regions_in_type_of_node(\
977             ty={}, ty0={}, id={}, minimum_lifetime={:?})",
978            ty_to_str(tcx, ty), ty_to_str(tcx, ty0),
979            id, minimum_lifetime);
980     constrain_regions_in_type(rcx, minimum_lifetime, origin, ty);
981 }
982
983 fn constrain_regions_in_type(
984     rcx: &mut Rcx,
985     minimum_lifetime: ty::Region,
986     origin: infer::SubregionOrigin,
987     ty: ty::t) {
988     /*!
989      * Requires that any regions which appear in `ty` must be
990      * superregions of `minimum_lifetime`.  Also enforces the constraint
991      * that given a pointer type `&'r T`, T must not contain regions
992      * that outlive 'r, as well as analogous constraints for other
993      * lifetime'd types.
994      *
995      * This check prevents regions from being used outside of the block in
996      * which they are valid.  Recall that regions represent blocks of
997      * code or expressions: this requirement basically says "any place
998      * that uses or may use a region R must be within the block of
999      * code that R corresponds to."
1000      */
1001
1002     let tcx = rcx.fcx.ccx.tcx;
1003
1004     debug!("constrain_regions_in_type(minimum_lifetime={}, ty={})",
1005            region_to_str(tcx, "", false, minimum_lifetime),
1006            ty_to_str(tcx, ty));
1007
1008     relate_nested_regions(tcx, Some(minimum_lifetime), ty, |r_sub, r_sup| {
1009         debug!("relate_nested_regions(r_sub={}, r_sup={})",
1010                 r_sub.repr(tcx),
1011                 r_sup.repr(tcx));
1012
1013         if r_sup.is_bound() || r_sub.is_bound() {
1014             // a bound region is one which appears inside an fn type.
1015             // (e.g., the `&` in `fn(&T)`).  Such regions need not be
1016             // constrained by `minimum_lifetime` as they are placeholders
1017             // for regions that are as-yet-unknown.
1018         } else if r_sub == minimum_lifetime {
1019             rcx.fcx.mk_subr(
1020                 true, origin.clone(),
1021                 r_sub, r_sup);
1022         } else {
1023             rcx.fcx.mk_subr(
1024                 true, infer::ReferenceOutlivesReferent(ty, origin.span()),
1025                 r_sub, r_sup);
1026         }
1027     });
1028 }
1029
1030 fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
1031                mutability: ast::Mutability, base: &ast::Expr) {
1032     /*!
1033      * Computes the guarantor for an expression `&base` and then
1034      * ensures that the lifetime of the resulting pointer is linked
1035      * to the lifetime of its guarantor (if any).
1036      */
1037
1038     debug!("link_addr_of(base=?)");
1039
1040     let cmt = {
1041         let mc = mc::MemCategorizationContext { typer: &*rcx };
1042         ignore_err!(mc.cat_expr(base))
1043     };
1044     link_region_from_node_type(rcx, expr.span, expr.id, mutability, cmt);
1045 }
1046
1047 fn link_local(rcx: &Rcx, local: &ast::Local) {
1048     /*!
1049      * Computes the guarantors for any ref bindings in a `let` and
1050      * then ensures that the lifetime of the resulting pointer is
1051      * linked to the lifetime of the initialization expression.
1052      */
1053
1054     debug!("regionck::for_local()");
1055     let init_expr = match local.init {
1056         None => { return; }
1057         Some(expr) => expr,
1058     };
1059     let mc = mc::MemCategorizationContext { typer: rcx };
1060     let discr_cmt = ignore_err!(mc.cat_expr(init_expr));
1061     link_pattern(mc, discr_cmt, local.pat);
1062 }
1063
1064 fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) {
1065     /*!
1066      * Computes the guarantors for any ref bindings in a match and
1067      * then ensures that the lifetime of the resulting pointer is
1068      * linked to the lifetime of its guarantor (if any).
1069      */
1070
1071     debug!("regionck::for_match()");
1072     let mc = mc::MemCategorizationContext { typer: rcx };
1073     let discr_cmt = ignore_err!(mc.cat_expr(discr));
1074     debug!("discr_cmt={}", discr_cmt.repr(mc.typer.tcx()));
1075     for arm in arms.iter() {
1076         for &root_pat in arm.pats.iter() {
1077             link_pattern(mc, discr_cmt.clone(), root_pat);
1078         }
1079     }
1080 }
1081
1082 fn link_pattern(mc: mc::MemCategorizationContext<&Rcx>,
1083                 discr_cmt: mc::cmt,
1084                 root_pat: &ast::Pat) {
1085     /*!
1086      * Link lifetimes of any ref bindings in `root_pat` to
1087      * the pointers found in the discriminant, if needed.
1088      */
1089
1090     let _ = mc.cat_pattern(discr_cmt, root_pat, |mc, sub_cmt, sub_pat| {
1091             match sub_pat.node {
1092                 // `ref x` pattern
1093                 ast::PatIdent(ast::BindByRef(mutbl), _, _) => {
1094                     link_region_from_node_type(
1095                         mc.typer, sub_pat.span, sub_pat.id,
1096                         mutbl, sub_cmt);
1097                 }
1098
1099                 // `[_, ..slice, _]` pattern
1100                 ast::PatVec(_, Some(slice_pat), _) => {
1101                     match mc.cat_slice_pattern(sub_cmt, slice_pat) {
1102                         Ok((slice_cmt, slice_mutbl, slice_r)) => {
1103                             link_region(mc.typer, sub_pat.span, slice_r,
1104                                         ty::BorrowKind::from_mutbl(slice_mutbl),
1105                                         slice_cmt);
1106                         }
1107                         Err(()) => {}
1108                     }
1109                 }
1110                 _ => {}
1111             }
1112         });
1113 }
1114
1115 fn link_autoref(rcx: &Rcx,
1116                 expr: &ast::Expr,
1117                 autoderefs: uint,
1118                 autoref: &ty::AutoRef) {
1119     /*!
1120      * Link lifetime of borrowed pointer resulting from autoref
1121      * to lifetimes in the value being autoref'd.
1122      */
1123
1124     debug!("link_autoref(autoref={:?})", autoref);
1125     let mc = mc::MemCategorizationContext { typer: rcx };
1126     let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
1127     debug!("expr_cmt={}", expr_cmt.repr(mc.typer.tcx()));
1128
1129     match *autoref {
1130         ty::AutoPtr(r, m) => {
1131             link_region(mc.typer, expr.span, r,
1132                         ty::BorrowKind::from_mutbl(m), expr_cmt);
1133         }
1134
1135         ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => {
1136             let cmt_index = mc.cat_index(expr, expr_cmt, autoderefs+1);
1137             link_region(mc.typer, expr.span, r,
1138                         ty::BorrowKind::from_mutbl(m), cmt_index);
1139         }
1140
1141         ty::AutoBorrowObj(r, m) => {
1142             let cmt_deref = mc.cat_deref_obj(expr, expr_cmt);
1143             link_region(mc.typer, expr.span, r,
1144                         ty::BorrowKind::from_mutbl(m), cmt_deref);
1145         }
1146
1147         ty::AutoUnsafe(_) => {}
1148     }
1149 }
1150
1151 fn link_by_ref(rcx: &Rcx,
1152                expr: &ast::Expr,
1153                callee_scope: ast::NodeId) {
1154     /*!
1155      * Computes the guarantor for cases where the `expr` is
1156      * being passed by implicit reference and must outlive
1157      * `callee_scope`.
1158      */
1159
1160     let tcx = rcx.tcx();
1161     debug!("link_by_ref(expr={}, callee_scope={})",
1162            expr.repr(tcx), callee_scope);
1163     let mc = mc::MemCategorizationContext { typer: rcx };
1164     let expr_cmt = ignore_err!(mc.cat_expr(expr));
1165     let region_min = ty::ReScope(callee_scope);
1166     link_region(mc.typer, expr.span, region_min, ty::ImmBorrow, expr_cmt);
1167 }
1168
1169 fn link_region_from_node_type(rcx: &Rcx,
1170                               span: Span,
1171                               id: ast::NodeId,
1172                               mutbl: ast::Mutability,
1173                               cmt_borrowed: mc::cmt) {
1174     /*!
1175      * Like `link_region()`, except that the region is
1176      * extracted from the type of `id`, which must be some
1177      * reference (`&T`, `&str`, etc).
1178      */
1179
1180     let rptr_ty = rcx.resolve_node_type(id);
1181     if !ty::type_is_bot(rptr_ty) && !ty::type_is_error(rptr_ty) {
1182         let tcx = rcx.fcx.ccx.tcx;
1183         debug!("rptr_ty={}", ty_to_str(tcx, rptr_ty));
1184         let r = ty::ty_region(tcx, span, rptr_ty);
1185         link_region(rcx, span, r, ty::BorrowKind::from_mutbl(mutbl),
1186                     cmt_borrowed);
1187     }
1188 }
1189
1190 fn link_region(rcx: &Rcx,
1191                span: Span,
1192                region_min: ty::Region,
1193                kind: ty::BorrowKind,
1194                cmt_borrowed: mc::cmt) {
1195     /*!
1196      * Informs the inference engine that a borrow of `cmt`
1197      * must have the borrow kind `kind` and lifetime `region_min`.
1198      * If `cmt` is a deref of a region pointer with
1199      * lifetime `r_borrowed`, this will add the constraint that
1200      * `region_min <= r_borrowed`.
1201      */
1202
1203     // Iterate through all the things that must be live at least
1204     // for the lifetime `region_min` for the borrow to be valid:
1205     let mut cmt_borrowed = cmt_borrowed;
1206     loop {
1207         debug!("link_region(region_min={}, kind={}, cmt_borrowed={})",
1208                region_min.repr(rcx.tcx()),
1209                kind.repr(rcx.tcx()),
1210                cmt_borrowed.repr(rcx.tcx()));
1211         match cmt_borrowed.cat.clone() {
1212             mc::cat_deref(base, _, mc::BorrowedPtr(_, r_borrowed)) => {
1213                 // References to an upvar `x` are translated to
1214                 // `*x`, since that is what happens in the
1215                 // underlying machine.  We detect such references
1216                 // and treat them slightly differently, both to
1217                 // offer better error messages and because we need
1218                 // to infer the kind of borrow (mut, const, etc)
1219                 // to use for each upvar.
1220                 let cause = match base.cat {
1221                     mc::cat_upvar(ref upvar_id, _) => {
1222                         match rcx.fcx.inh.upvar_borrow_map.borrow_mut()
1223                                  .find_mut(upvar_id) {
1224                             Some(upvar_borrow) => {
1225                                 debug!("link_region: {} <= {}",
1226                                        region_min.repr(rcx.tcx()),
1227                                        upvar_borrow.region.repr(rcx.tcx()));
1228                                 adjust_upvar_borrow_kind_for_loan(
1229                                     *upvar_id,
1230                                     upvar_borrow,
1231                                     kind);
1232                                 infer::ReborrowUpvar(span, *upvar_id)
1233                             }
1234                             None => {
1235                                 rcx.tcx().sess.span_bug(
1236                                     span,
1237                                     format!("Illegal upvar id: {}",
1238                                             upvar_id.repr(rcx.tcx())));
1239                             }
1240                         }
1241                     }
1242
1243                     _ => {
1244                         infer::Reborrow(span)
1245                     }
1246                 };
1247
1248                 debug!("link_region: {} <= {}",
1249                        region_min.repr(rcx.tcx()),
1250                        r_borrowed.repr(rcx.tcx()));
1251                 rcx.fcx.mk_subr(true, cause, region_min, r_borrowed);
1252
1253                 if kind != ty::ImmBorrow {
1254                     // If this is a mutable borrow, then the thing
1255                     // being borrowed will have to be unique.
1256                     // In user code, this means it must be an `&mut`
1257                     // borrow, but for an upvar, we might opt
1258                     // for an immutable-unique borrow.
1259                     adjust_upvar_borrow_kind_for_unique(rcx, base);
1260                 }
1261
1262                 // Borrowing an `&mut` pointee for `region_min` is
1263                 // only valid if the pointer resides in a unique
1264                 // location which is itself valid for
1265                 // `region_min`.  We don't care about the unique
1266                 // part, but we may need to influence the
1267                 // inference to ensure that the location remains
1268                 // valid.
1269                 //
1270                 // FIXME(#8624) fixing borrowck will require this
1271                 // if m == ast::m_mutbl {
1272                 //    cmt_borrowed = cmt_base;
1273                 // } else {
1274                 //    return;
1275                 // }
1276                 return;
1277             }
1278             mc::cat_discr(cmt_base, _) |
1279             mc::cat_downcast(cmt_base) |
1280             mc::cat_deref(cmt_base, _, mc::OwnedPtr) |
1281             mc::cat_interior(cmt_base, _) => {
1282                 // Interior or owned data requires its base to be valid
1283                 cmt_borrowed = cmt_base;
1284             }
1285             mc::cat_deref(_, _, mc::GcPtr(..)) |
1286             mc::cat_deref(_, _, mc::UnsafePtr(..)) |
1287             mc::cat_static_item |
1288             mc::cat_copied_upvar(..) |
1289             mc::cat_local(..) |
1290             mc::cat_arg(..) |
1291             mc::cat_upvar(..) |
1292             mc::cat_rvalue(..) => {
1293                 // These are all "base cases" with independent lifetimes
1294                 // that are not subject to inference
1295                 return;
1296             }
1297         }
1298     }
1299 }
1300
1301 fn adjust_borrow_kind_for_assignment_lhs(rcx: &Rcx,
1302                                          lhs: &ast::Expr) {
1303     /*!
1304      * Adjusts the inferred borrow_kind as needed to account
1305      * for upvars that are assigned to in an assignment
1306      * expression.
1307      */
1308
1309     let mc = mc::MemCategorizationContext { typer: rcx };
1310     let cmt = ignore_err!(mc.cat_expr(lhs));
1311     adjust_upvar_borrow_kind_for_mut(mc.typer, cmt);
1312 }
1313
1314 fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx,
1315                                     cmt: mc::cmt) {
1316     let mut cmt = cmt;
1317     loop {
1318         debug!("adjust_upvar_borrow_kind_for_mut(cmt={})",
1319                cmt.repr(rcx.tcx()));
1320
1321         match cmt.cat.clone() {
1322             mc::cat_deref(base, _, mc::OwnedPtr) |
1323             mc::cat_interior(base, _) |
1324             mc::cat_downcast(base) |
1325             mc::cat_discr(base, _) => {
1326                 // Interior or owned data is mutable if base is
1327                 // mutable, so iterate to the base.
1328                 cmt = base;
1329                 continue;
1330             }
1331
1332             mc::cat_deref(base, _, mc::BorrowedPtr(..)) => {
1333                 match base.cat {
1334                     mc::cat_upvar(ref upvar_id, _) => {
1335                         // if this is an implicit deref of an
1336                         // upvar, then we need to modify the
1337                         // borrow_kind of the upvar to make sure it
1338                         // is inferred to mutable if necessary
1339                         let mut upvar_borrow_map =
1340                             rcx.fcx.inh.upvar_borrow_map.borrow_mut();
1341                         let ub = upvar_borrow_map.get_mut(upvar_id);
1342                         return adjust_upvar_borrow_kind(*upvar_id, ub, ty::MutBorrow);
1343                     }
1344
1345                     _ => {}
1346                 }
1347
1348                 // assignment to deref of an `&mut`
1349                 // borrowed pointer implies that the
1350                 // pointer itself must be unique, but not
1351                 // necessarily *mutable*
1352                 return adjust_upvar_borrow_kind_for_unique(rcx, base);
1353             }
1354
1355             mc::cat_deref(_, _, mc::UnsafePtr(..)) |
1356             mc::cat_deref(_, _, mc::GcPtr) |
1357             mc::cat_static_item |
1358             mc::cat_rvalue(_) |
1359             mc::cat_copied_upvar(_) |
1360             mc::cat_local(_) |
1361             mc::cat_arg(_) |
1362             mc::cat_upvar(..) => {
1363                 return;
1364             }
1365         }
1366     }
1367 }
1368
1369 fn adjust_upvar_borrow_kind_for_unique(rcx: &Rcx, cmt: mc::cmt) {
1370     let mut cmt = cmt;
1371     loop {
1372         debug!("adjust_upvar_borrow_kind_for_unique(cmt={})",
1373                cmt.repr(rcx.tcx()));
1374
1375         match cmt.cat.clone() {
1376             mc::cat_deref(base, _, mc::OwnedPtr) |
1377             mc::cat_interior(base, _) |
1378             mc::cat_downcast(base) |
1379             mc::cat_discr(base, _) => {
1380                 // Interior or owned data is unique if base is
1381                 // unique.
1382                 cmt = base;
1383                 continue;
1384             }
1385
1386             mc::cat_deref(base, _, mc::BorrowedPtr(..)) => {
1387                 match base.cat {
1388                     mc::cat_upvar(ref upvar_id, _) => {
1389                         // if this is an implicit deref of an
1390                         // upvar, then we need to modify the
1391                         // borrow_kind of the upvar to make sure it
1392                         // is inferred to unique if necessary
1393                         let mut ub = rcx.fcx.inh.upvar_borrow_map.borrow_mut();
1394                         let ub = ub.get_mut(upvar_id);
1395                         return adjust_upvar_borrow_kind(*upvar_id, ub, ty::UniqueImmBorrow);
1396                     }
1397
1398                     _ => {}
1399                 }
1400
1401                 // for a borrowed pointer to be unique, its
1402                 // base must be unique
1403                 return adjust_upvar_borrow_kind_for_unique(rcx, base);
1404             }
1405
1406             mc::cat_deref(_, _, mc::UnsafePtr(..)) |
1407             mc::cat_deref(_, _, mc::GcPtr) |
1408             mc::cat_static_item |
1409             mc::cat_rvalue(_) |
1410             mc::cat_copied_upvar(_) |
1411             mc::cat_local(_) |
1412             mc::cat_arg(_) |
1413             mc::cat_upvar(..) => {
1414                 return;
1415             }
1416         }
1417     }
1418 }
1419
1420 fn link_upvar_borrow_kind_for_nested_closures(rcx: &mut Rcx,
1421                                               inner_upvar_id: ty::UpvarId,
1422                                               outer_upvar_id: ty::UpvarId) {
1423     /*!
1424      * Indicates that the borrow_kind of `outer_upvar_id` must
1425      * permit a reborrowing with the borrow_kind of `inner_upvar_id`.
1426      * This occurs in nested closures, see comment above at the call to
1427      * this function.
1428      */
1429
1430     debug!("link_upvar_borrow_kind: inner_upvar_id={:?} outer_upvar_id={:?}",
1431            inner_upvar_id, outer_upvar_id);
1432
1433     let mut upvar_borrow_map = rcx.fcx.inh.upvar_borrow_map.borrow_mut();
1434     let inner_borrow = upvar_borrow_map.get_copy(&inner_upvar_id);
1435     match upvar_borrow_map.find_mut(&outer_upvar_id) {
1436         Some(outer_borrow) => {
1437             adjust_upvar_borrow_kind(outer_upvar_id, outer_borrow, inner_borrow.kind);
1438         }
1439         None => { /* outer closure is not a stack closure */ }
1440     }
1441 }
1442
1443 fn adjust_upvar_borrow_kind_for_loan(upvar_id: ty::UpvarId,
1444                                      upvar_borrow: &mut ty::UpvarBorrow,
1445                                      kind: ty::BorrowKind) {
1446     debug!("adjust_upvar_borrow_kind_for_loan: upvar_id={:?} kind={:?} -> {:?}",
1447            upvar_id, upvar_borrow.kind, kind);
1448
1449     adjust_upvar_borrow_kind(upvar_id, upvar_borrow, kind)
1450 }
1451
1452 fn adjust_upvar_borrow_kind(upvar_id: ty::UpvarId,
1453                             upvar_borrow: &mut ty::UpvarBorrow,
1454                             kind: ty::BorrowKind) {
1455     /*!
1456      * We infer the borrow_kind with which to borrow upvars in a stack
1457      * closure. The borrow_kind basically follows a lattice of
1458      * `imm < unique-imm < mut`, moving from left to right as needed (but never
1459      * right to left). Here the argument `mutbl` is the borrow_kind that
1460      * is required by some particular use.
1461      */
1462
1463     debug!("adjust_upvar_borrow_kind: id={:?} kind=({:?} -> {:?})",
1464            upvar_id, upvar_borrow.kind, kind);
1465
1466     match (upvar_borrow.kind, kind) {
1467         // Take RHS:
1468         (ty::ImmBorrow, ty::UniqueImmBorrow) |
1469         (ty::ImmBorrow, ty::MutBorrow) |
1470         (ty::UniqueImmBorrow, ty::MutBorrow) => {
1471             upvar_borrow.kind = kind;
1472         }
1473         // Take LHS:
1474         (ty::ImmBorrow, ty::ImmBorrow) |
1475         (ty::UniqueImmBorrow, ty::ImmBorrow) |
1476         (ty::UniqueImmBorrow, ty::UniqueImmBorrow) |
1477         (ty::MutBorrow, _) => {
1478         }
1479     }
1480 }