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