]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/typeck/check/regionck.rs
Ignore tests broken by failing on ICE
[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<'fcx> mc::Typer for Rcx<'fcx> {
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 a 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 a 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::new(rcx);
758                     let expr_cmt = ignore_err!(mc.cat_expr(callee_expr));
759                     link_region(rcx, 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::new(rcx);
884                     let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
885                     link_region(rcx, 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_rptr(r_ptr, mt) => match ty::get(mt.ty).sty {
943             ty::ty_vec(_, None) | ty::ty_str => {
944                 rcx.fcx.mk_subr(true, infer::IndexSlice(index_expr.span),
945                                 r_index_expr, r_ptr);
946             }
947             _ => {}
948         },
949
950         _ => {}
951     }
952 }
953
954 fn constrain_regions_in_type_of_node(
955     rcx: &mut Rcx,
956     id: ast::NodeId,
957     minimum_lifetime: ty::Region,
958     origin: infer::SubregionOrigin) {
959     //! Guarantees that any lifetimes which appear in the type of
960     //! the node `id` (after applying adjustments) are valid for at
961     //! least `minimum_lifetime`
962
963     let tcx = rcx.fcx.tcx();
964
965     // Try to resolve the type.  If we encounter an error, then typeck
966     // is going to fail anyway, so just stop here and let typeck
967     // report errors later on in the writeback phase.
968     let ty0 = rcx.resolve_node_type(id);
969     let ty = ty::adjust_ty(tcx, origin.span(), id, ty0,
970                            rcx.fcx.inh.adjustments.borrow().find(&id),
971                            |method_call| rcx.resolve_method_type(method_call));
972     debug!("constrain_regions_in_type_of_node(\
973             ty={}, ty0={}, id={}, minimum_lifetime={:?})",
974            ty_to_str(tcx, ty), ty_to_str(tcx, ty0),
975            id, minimum_lifetime);
976     constrain_regions_in_type(rcx, minimum_lifetime, origin, ty);
977 }
978
979 fn constrain_regions_in_type(
980     rcx: &mut Rcx,
981     minimum_lifetime: ty::Region,
982     origin: infer::SubregionOrigin,
983     ty: ty::t) {
984     /*!
985      * Requires that any regions which appear in `ty` must be
986      * superregions of `minimum_lifetime`.  Also enforces the constraint
987      * that given a pointer type `&'r T`, T must not contain regions
988      * that outlive 'r, as well as analogous constraints for other
989      * lifetime'd types.
990      *
991      * This check prevents regions from being used outside of the block in
992      * which they are valid.  Recall that regions represent blocks of
993      * code or expressions: this requirement basically says "any place
994      * that uses or may use a region R must be within the block of
995      * code that R corresponds to."
996      */
997
998     let tcx = rcx.fcx.ccx.tcx;
999
1000     debug!("constrain_regions_in_type(minimum_lifetime={}, ty={})",
1001            region_to_str(tcx, "", false, minimum_lifetime),
1002            ty_to_str(tcx, ty));
1003
1004     relate_nested_regions(tcx, Some(minimum_lifetime), ty, |r_sub, r_sup| {
1005         debug!("relate_nested_regions(r_sub={}, r_sup={})",
1006                 r_sub.repr(tcx),
1007                 r_sup.repr(tcx));
1008
1009         if r_sup.is_bound() || r_sub.is_bound() {
1010             // a bound region is one which appears inside an fn type.
1011             // (e.g., the `&` in `fn(&T)`).  Such regions need not be
1012             // constrained by `minimum_lifetime` as they are placeholders
1013             // for regions that are as-yet-unknown.
1014         } else if r_sub == minimum_lifetime {
1015             rcx.fcx.mk_subr(
1016                 true, origin.clone(),
1017                 r_sub, r_sup);
1018         } else {
1019             rcx.fcx.mk_subr(
1020                 true, infer::ReferenceOutlivesReferent(ty, origin.span()),
1021                 r_sub, r_sup);
1022         }
1023     });
1024 }
1025
1026 fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
1027                mutability: ast::Mutability, base: &ast::Expr) {
1028     /*!
1029      * Computes the guarantor for an expression `&base` and then
1030      * ensures that the lifetime of the resulting pointer is linked
1031      * to the lifetime of its guarantor (if any).
1032      */
1033
1034     debug!("link_addr_of(base=?)");
1035
1036     let cmt = {
1037         let mc = mc::MemCategorizationContext::new(rcx);
1038         ignore_err!(mc.cat_expr(base))
1039     };
1040     link_region_from_node_type(rcx, expr.span, expr.id, mutability, cmt);
1041 }
1042
1043 fn link_local(rcx: &Rcx, local: &ast::Local) {
1044     /*!
1045      * Computes the guarantors for any ref bindings in a `let` and
1046      * then ensures that the lifetime of the resulting pointer is
1047      * linked to the lifetime of the initialization expression.
1048      */
1049
1050     debug!("regionck::for_local()");
1051     let init_expr = match local.init {
1052         None => { return; }
1053         Some(expr) => expr,
1054     };
1055     let mc = mc::MemCategorizationContext::new(rcx);
1056     let discr_cmt = ignore_err!(mc.cat_expr(init_expr));
1057     link_pattern(rcx, mc, discr_cmt, local.pat);
1058 }
1059
1060 fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) {
1061     /*!
1062      * Computes the guarantors for any ref bindings in a match and
1063      * then ensures that the lifetime of the resulting pointer is
1064      * linked to the lifetime of its guarantor (if any).
1065      */
1066
1067     debug!("regionck::for_match()");
1068     let mc = mc::MemCategorizationContext::new(rcx);
1069     let discr_cmt = ignore_err!(mc.cat_expr(discr));
1070     debug!("discr_cmt={}", discr_cmt.repr(rcx.tcx()));
1071     for arm in arms.iter() {
1072         for &root_pat in arm.pats.iter() {
1073             link_pattern(rcx, mc, discr_cmt.clone(), root_pat);
1074         }
1075     }
1076 }
1077
1078 fn link_pattern(rcx: &Rcx,
1079                 mc: mc::MemCategorizationContext<Rcx>,
1080                 discr_cmt: mc::cmt,
1081                 root_pat: &ast::Pat) {
1082     /*!
1083      * Link lifetimes of any ref bindings in `root_pat` to
1084      * the pointers found in the discriminant, if needed.
1085      */
1086
1087     let _ = mc.cat_pattern(discr_cmt, root_pat, |mc, sub_cmt, sub_pat| {
1088             match sub_pat.node {
1089                 // `ref x` pattern
1090                 ast::PatIdent(ast::BindByRef(mutbl), _, _) => {
1091                     link_region_from_node_type(
1092                         rcx, sub_pat.span, sub_pat.id,
1093                         mutbl, sub_cmt);
1094                 }
1095
1096                 // `[_, ..slice, _]` pattern
1097                 ast::PatVec(_, Some(slice_pat), _) => {
1098                     match mc.cat_slice_pattern(sub_cmt, slice_pat) {
1099                         Ok((slice_cmt, slice_mutbl, slice_r)) => {
1100                             link_region(rcx, sub_pat.span, slice_r,
1101                                         ty::BorrowKind::from_mutbl(slice_mutbl),
1102                                         slice_cmt);
1103                         }
1104                         Err(()) => {}
1105                     }
1106                 }
1107                 _ => {}
1108             }
1109         });
1110 }
1111
1112 fn link_autoref(rcx: &Rcx,
1113                 expr: &ast::Expr,
1114                 autoderefs: uint,
1115                 autoref: &ty::AutoRef) {
1116     /*!
1117      * Link lifetime of borrowed pointer resulting from autoref
1118      * to lifetimes in the value being autoref'd.
1119      */
1120
1121     debug!("link_autoref(autoref={:?})", autoref);
1122     let mc = mc::MemCategorizationContext::new(rcx);
1123     let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
1124     debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx()));
1125
1126     match *autoref {
1127         ty::AutoPtr(r, m) => {
1128             link_region(rcx, expr.span, r,
1129                         ty::BorrowKind::from_mutbl(m), expr_cmt);
1130         }
1131
1132         ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => {
1133             let cmt_index = mc.cat_index(expr, expr_cmt, autoderefs+1);
1134             link_region(rcx, expr.span, r,
1135                         ty::BorrowKind::from_mutbl(m), cmt_index);
1136         }
1137
1138         ty::AutoBorrowObj(r, m) => {
1139             let cmt_deref = mc.cat_deref_obj(expr, expr_cmt);
1140             link_region(rcx, expr.span, r,
1141                         ty::BorrowKind::from_mutbl(m), cmt_deref);
1142         }
1143
1144         ty::AutoUnsafe(_) => {}
1145     }
1146 }
1147
1148 fn link_by_ref(rcx: &Rcx,
1149                expr: &ast::Expr,
1150                callee_scope: ast::NodeId) {
1151     /*!
1152      * Computes the guarantor for cases where the `expr` is
1153      * being passed by implicit reference and must outlive
1154      * `callee_scope`.
1155      */
1156
1157     let tcx = rcx.tcx();
1158     debug!("link_by_ref(expr={}, callee_scope={})",
1159            expr.repr(tcx), callee_scope);
1160     let mc = mc::MemCategorizationContext::new(rcx);
1161     let expr_cmt = ignore_err!(mc.cat_expr(expr));
1162     let region_min = ty::ReScope(callee_scope);
1163     link_region(rcx, expr.span, region_min, ty::ImmBorrow, expr_cmt);
1164 }
1165
1166 fn link_region_from_node_type(rcx: &Rcx,
1167                               span: Span,
1168                               id: ast::NodeId,
1169                               mutbl: ast::Mutability,
1170                               cmt_borrowed: mc::cmt) {
1171     /*!
1172      * Like `link_region()`, except that the region is
1173      * extracted from the type of `id`, which must be some
1174      * reference (`&T`, `&str`, etc).
1175      */
1176
1177     let rptr_ty = rcx.resolve_node_type(id);
1178     if !ty::type_is_bot(rptr_ty) && !ty::type_is_error(rptr_ty) {
1179         let tcx = rcx.fcx.ccx.tcx;
1180         debug!("rptr_ty={}", ty_to_str(tcx, rptr_ty));
1181         let r = ty::ty_region(tcx, span, rptr_ty);
1182         link_region(rcx, span, r, ty::BorrowKind::from_mutbl(mutbl),
1183                     cmt_borrowed);
1184     }
1185 }
1186
1187 fn link_region(rcx: &Rcx,
1188                span: Span,
1189                region_min: ty::Region,
1190                kind: ty::BorrowKind,
1191                cmt_borrowed: mc::cmt) {
1192     /*!
1193      * Informs the inference engine that a borrow of `cmt`
1194      * must have the borrow kind `kind` and lifetime `region_min`.
1195      * If `cmt` is a deref of a region pointer with
1196      * lifetime `r_borrowed`, this will add the constraint that
1197      * `region_min <= r_borrowed`.
1198      */
1199
1200     // Iterate through all the things that must be live at least
1201     // for the lifetime `region_min` for the borrow to be valid:
1202     let mut cmt_borrowed = cmt_borrowed;
1203     loop {
1204         debug!("link_region(region_min={}, kind={}, cmt_borrowed={})",
1205                region_min.repr(rcx.tcx()),
1206                kind.repr(rcx.tcx()),
1207                cmt_borrowed.repr(rcx.tcx()));
1208         match cmt_borrowed.cat.clone() {
1209             mc::cat_deref(base, _, mc::BorrowedPtr(_, r_borrowed)) => {
1210                 // References to an upvar `x` are translated to
1211                 // `*x`, since that is what happens in the
1212                 // underlying machine.  We detect such references
1213                 // and treat them slightly differently, both to
1214                 // offer better error messages and because we need
1215                 // to infer the kind of borrow (mut, const, etc)
1216                 // to use for each upvar.
1217                 let cause = match base.cat {
1218                     mc::cat_upvar(ref upvar_id, _) => {
1219                         match rcx.fcx.inh.upvar_borrow_map.borrow_mut()
1220                                  .find_mut(upvar_id) {
1221                             Some(upvar_borrow) => {
1222                                 debug!("link_region: {} <= {}",
1223                                        region_min.repr(rcx.tcx()),
1224                                        upvar_borrow.region.repr(rcx.tcx()));
1225                                 adjust_upvar_borrow_kind_for_loan(
1226                                     *upvar_id,
1227                                     upvar_borrow,
1228                                     kind);
1229                                 infer::ReborrowUpvar(span, *upvar_id)
1230                             }
1231                             None => {
1232                                 rcx.tcx().sess.span_bug(
1233                                     span,
1234                                     format!("Illegal upvar id: {}",
1235                                             upvar_id.repr(rcx.tcx())));
1236                             }
1237                         }
1238                     }
1239
1240                     _ => {
1241                         infer::Reborrow(span)
1242                     }
1243                 };
1244
1245                 debug!("link_region: {} <= {}",
1246                        region_min.repr(rcx.tcx()),
1247                        r_borrowed.repr(rcx.tcx()));
1248                 rcx.fcx.mk_subr(true, cause, region_min, r_borrowed);
1249
1250                 if kind != ty::ImmBorrow {
1251                     // If this is a mutable borrow, then the thing
1252                     // being borrowed will have to be unique.
1253                     // In user code, this means it must be an `&mut`
1254                     // borrow, but for an upvar, we might opt
1255                     // for an immutable-unique borrow.
1256                     adjust_upvar_borrow_kind_for_unique(rcx, base);
1257                 }
1258
1259                 // Borrowing an `&mut` pointee for `region_min` is
1260                 // only valid if the pointer resides in a unique
1261                 // location which is itself valid for
1262                 // `region_min`.  We don't care about the unique
1263                 // part, but we may need to influence the
1264                 // inference to ensure that the location remains
1265                 // valid.
1266                 //
1267                 // FIXME(#8624) fixing borrowck will require this
1268                 // if m == ast::m_mutbl {
1269                 //    cmt_borrowed = cmt_base;
1270                 // } else {
1271                 //    return;
1272                 // }
1273                 return;
1274             }
1275             mc::cat_discr(cmt_base, _) |
1276             mc::cat_downcast(cmt_base) |
1277             mc::cat_deref(cmt_base, _, mc::GcPtr(..)) |
1278             mc::cat_deref(cmt_base, _, mc::OwnedPtr) |
1279             mc::cat_interior(cmt_base, _) => {
1280                 // Interior or owned data requires its base to be valid
1281                 cmt_borrowed = cmt_base;
1282             }
1283             mc::cat_deref(_, _, mc::UnsafePtr(..)) |
1284             mc::cat_static_item |
1285             mc::cat_copied_upvar(..) |
1286             mc::cat_local(..) |
1287             mc::cat_arg(..) |
1288             mc::cat_upvar(..) |
1289             mc::cat_rvalue(..) => {
1290                 // These are all "base cases" with independent lifetimes
1291                 // that are not subject to inference
1292                 return;
1293             }
1294         }
1295     }
1296 }
1297
1298 fn adjust_borrow_kind_for_assignment_lhs(rcx: &Rcx,
1299                                          lhs: &ast::Expr) {
1300     /*!
1301      * Adjusts the inferred borrow_kind as needed to account
1302      * for upvars that are assigned to in an assignment
1303      * expression.
1304      */
1305
1306     let mc = mc::MemCategorizationContext::new(rcx);
1307     let cmt = ignore_err!(mc.cat_expr(lhs));
1308     adjust_upvar_borrow_kind_for_mut(rcx, cmt);
1309 }
1310
1311 fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx,
1312                                     cmt: mc::cmt) {
1313     let mut cmt = cmt;
1314     loop {
1315         debug!("adjust_upvar_borrow_kind_for_mut(cmt={})",
1316                cmt.repr(rcx.tcx()));
1317
1318         match cmt.cat.clone() {
1319             mc::cat_deref(base, _, mc::OwnedPtr) |
1320             mc::cat_interior(base, _) |
1321             mc::cat_downcast(base) |
1322             mc::cat_discr(base, _) => {
1323                 // Interior or owned data is mutable if base is
1324                 // mutable, so iterate to the base.
1325                 cmt = base;
1326                 continue;
1327             }
1328
1329             mc::cat_deref(base, _, mc::BorrowedPtr(..)) => {
1330                 match base.cat {
1331                     mc::cat_upvar(ref upvar_id, _) => {
1332                         // if this is an implicit deref of an
1333                         // upvar, then we need to modify the
1334                         // borrow_kind of the upvar to make sure it
1335                         // is inferred to mutable if necessary
1336                         let mut upvar_borrow_map =
1337                             rcx.fcx.inh.upvar_borrow_map.borrow_mut();
1338                         let ub = upvar_borrow_map.get_mut(upvar_id);
1339                         return adjust_upvar_borrow_kind(*upvar_id, ub, ty::MutBorrow);
1340                     }
1341
1342                     _ => {}
1343                 }
1344
1345                 // assignment to deref of an `&mut`
1346                 // borrowed pointer implies that the
1347                 // pointer itself must be unique, but not
1348                 // necessarily *mutable*
1349                 return adjust_upvar_borrow_kind_for_unique(rcx, base);
1350             }
1351
1352             mc::cat_deref(_, _, mc::UnsafePtr(..)) |
1353             mc::cat_deref(_, _, mc::GcPtr) |
1354             mc::cat_static_item |
1355             mc::cat_rvalue(_) |
1356             mc::cat_copied_upvar(_) |
1357             mc::cat_local(_) |
1358             mc::cat_arg(_) |
1359             mc::cat_upvar(..) => {
1360                 return;
1361             }
1362         }
1363     }
1364 }
1365
1366 fn adjust_upvar_borrow_kind_for_unique(rcx: &Rcx, cmt: mc::cmt) {
1367     let mut cmt = cmt;
1368     loop {
1369         debug!("adjust_upvar_borrow_kind_for_unique(cmt={})",
1370                cmt.repr(rcx.tcx()));
1371
1372         match cmt.cat.clone() {
1373             mc::cat_deref(base, _, mc::OwnedPtr) |
1374             mc::cat_interior(base, _) |
1375             mc::cat_downcast(base) |
1376             mc::cat_discr(base, _) => {
1377                 // Interior or owned data is unique if base is
1378                 // unique.
1379                 cmt = base;
1380                 continue;
1381             }
1382
1383             mc::cat_deref(base, _, mc::BorrowedPtr(..)) => {
1384                 match base.cat {
1385                     mc::cat_upvar(ref upvar_id, _) => {
1386                         // if this is an implicit deref of an
1387                         // upvar, then we need to modify the
1388                         // borrow_kind of the upvar to make sure it
1389                         // is inferred to unique if necessary
1390                         let mut ub = rcx.fcx.inh.upvar_borrow_map.borrow_mut();
1391                         let ub = ub.get_mut(upvar_id);
1392                         return adjust_upvar_borrow_kind(*upvar_id, ub, ty::UniqueImmBorrow);
1393                     }
1394
1395                     _ => {}
1396                 }
1397
1398                 // for a borrowed pointer to be unique, its
1399                 // base must be unique
1400                 return adjust_upvar_borrow_kind_for_unique(rcx, base);
1401             }
1402
1403             mc::cat_deref(_, _, mc::UnsafePtr(..)) |
1404             mc::cat_deref(_, _, mc::GcPtr) |
1405             mc::cat_static_item |
1406             mc::cat_rvalue(_) |
1407             mc::cat_copied_upvar(_) |
1408             mc::cat_local(_) |
1409             mc::cat_arg(_) |
1410             mc::cat_upvar(..) => {
1411                 return;
1412             }
1413         }
1414     }
1415 }
1416
1417 fn link_upvar_borrow_kind_for_nested_closures(rcx: &mut Rcx,
1418                                               inner_upvar_id: ty::UpvarId,
1419                                               outer_upvar_id: ty::UpvarId) {
1420     /*!
1421      * Indicates that the borrow_kind of `outer_upvar_id` must
1422      * permit a reborrowing with the borrow_kind of `inner_upvar_id`.
1423      * This occurs in nested closures, see comment above at the call to
1424      * this function.
1425      */
1426
1427     debug!("link_upvar_borrow_kind: inner_upvar_id={:?} outer_upvar_id={:?}",
1428            inner_upvar_id, outer_upvar_id);
1429
1430     let mut upvar_borrow_map = rcx.fcx.inh.upvar_borrow_map.borrow_mut();
1431     let inner_borrow = upvar_borrow_map.get_copy(&inner_upvar_id);
1432     match upvar_borrow_map.find_mut(&outer_upvar_id) {
1433         Some(outer_borrow) => {
1434             adjust_upvar_borrow_kind(outer_upvar_id, outer_borrow, inner_borrow.kind);
1435         }
1436         None => { /* outer closure is not a stack closure */ }
1437     }
1438 }
1439
1440 fn adjust_upvar_borrow_kind_for_loan(upvar_id: ty::UpvarId,
1441                                      upvar_borrow: &mut ty::UpvarBorrow,
1442                                      kind: ty::BorrowKind) {
1443     debug!("adjust_upvar_borrow_kind_for_loan: upvar_id={:?} kind={:?} -> {:?}",
1444            upvar_id, upvar_borrow.kind, kind);
1445
1446     adjust_upvar_borrow_kind(upvar_id, upvar_borrow, kind)
1447 }
1448
1449 fn adjust_upvar_borrow_kind(upvar_id: ty::UpvarId,
1450                             upvar_borrow: &mut ty::UpvarBorrow,
1451                             kind: ty::BorrowKind) {
1452     /*!
1453      * We infer the borrow_kind with which to borrow upvars in a stack
1454      * closure. The borrow_kind basically follows a lattice of
1455      * `imm < unique-imm < mut`, moving from left to right as needed (but never
1456      * right to left). Here the argument `mutbl` is the borrow_kind that
1457      * is required by some particular use.
1458      */
1459
1460     debug!("adjust_upvar_borrow_kind: id={:?} kind=({:?} -> {:?})",
1461            upvar_id, upvar_borrow.kind, kind);
1462
1463     match (upvar_borrow.kind, kind) {
1464         // Take RHS:
1465         (ty::ImmBorrow, ty::UniqueImmBorrow) |
1466         (ty::ImmBorrow, ty::MutBorrow) |
1467         (ty::UniqueImmBorrow, ty::MutBorrow) => {
1468             upvar_borrow.kind = kind;
1469         }
1470         // Take LHS:
1471         (ty::ImmBorrow, ty::ImmBorrow) |
1472         (ty::UniqueImmBorrow, ty::ImmBorrow) |
1473         (ty::UniqueImmBorrow, ty::UniqueImmBorrow) |
1474         (ty::MutBorrow, _) => {
1475         }
1476     }
1477 }