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 = box 3, w = box 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(box 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(box 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(box ty::ClosureTy {
639 store: ty::RegionTraitStore(..),
640 ..
641 }) => {
642 freevars::with_freevars(tcx, expr.id, |freevars| {
643 propagate_upupvar_borrow_kind(rcx, expr, freevars);
644 })
645 }
646 _ => ()
647 }
648
649 fn constrain_free_variables(rcx: &mut Rcx,
650 region: ty::Region,
651 expr: &ast::Expr,
652 freevars: &[freevars::freevar_entry]) {
653 /*!
654 * Make sure that all free variables referenced inside the closure
655 * outlive the closure itself. Also, create an entry in the
656 * upvar_borrows map with a region.
657 */
658
659 let tcx = rcx.fcx.ccx.tcx;
660 let infcx = rcx.fcx.infcx();
661 debug!("constrain_free_variables({}, {})",
662 region.repr(tcx), expr.repr(tcx));
663 for freevar in freevars.iter() {
664 debug!("freevar def is {:?}", freevar.def);
665
666 // Identify the variable being closed over and its node-id.
667 let def = freevar.def;
668 let def_id = ast_util::def_id_of_def(def);
669 assert!(def_id.krate == ast::LOCAL_CRATE);
670 let upvar_id = ty::UpvarId { var_id: def_id.node,
671 closure_expr_id: expr.id };
672
673 // Create a region variable to represent this borrow. This borrow
674 // must outlive the region on the closure.
675 let origin = infer::UpvarRegion(upvar_id, expr.span);
676 let freevar_region = infcx.next_region_var(origin);
677 rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node),
678 region, freevar_region);
679
680 // Create a UpvarBorrow entry. Note that we begin with a
681 // const borrow_kind, but change it to either mut or
682 // immutable as dictated by the uses.
683 let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow,
684 region: freevar_region };
685 rcx.fcx.inh.upvar_borrow_map.borrow_mut().insert(upvar_id,
686 upvar_borrow);
687
688 // Guarantee that the closure does not outlive the variable itself.
689 let en_region = region_of_def(rcx.fcx, def);
690 debug!("en_region = {}", en_region.repr(tcx));
691 rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node),
692 region, en_region);
693 }
694 }
695
696 fn propagate_upupvar_borrow_kind(rcx: &mut Rcx,
697 expr: &ast::Expr,
698 freevars: &[freevars::freevar_entry]) {
699 let tcx = rcx.fcx.ccx.tcx;
700 debug!("propagate_upupvar_borrow_kind({})", expr.repr(tcx));
701 for freevar in freevars.iter() {
702 // Because of the semi-hokey way that we are doing
703 // borrow_kind inference, we need to check for
704 // indirect dependencies, like so:
705 //
706 // let mut x = 0;
707 // outer_call(|| {
708 // inner_call(|| {
709 // x = 1;
710 // });
711 // });
712 //
713 // Here, the `inner_call` is basically "reborrowing" the
714 // outer pointer. With no other changes, `inner_call`
715 // would infer that it requires a mutable borrow, but
716 // `outer_call` would infer that a const borrow is
717 // sufficient. This is because we haven't linked the
718 // borrow_kind of the borrow that occurs in the inner
719 // closure to the borrow_kind of the borrow in the outer
720 // closure. Note that regions *are* naturally linked
721 // because we have a proper inference scheme there.
722 //
723 // Anyway, for borrow_kind, we basically go back over now
724 // after checking the inner closure (and hence
725 // determining the final borrow_kind) and propagate that as
726 // a constraint on the outer closure.
727 match freevar.def {
728 ast::DefUpvar(var_id, _, outer_closure_id, _) => {
729 // thing being captured is itself an upvar:
730 let outer_upvar_id = ty::UpvarId {
731 var_id: var_id,
732 closure_expr_id: outer_closure_id };
733 let inner_upvar_id = ty::UpvarId {
734 var_id: var_id,
735 closure_expr_id: expr.id };
736 link_upvar_borrow_kind_for_nested_closures(rcx,
737 inner_upvar_id,
738 outer_upvar_id);
739 }
740 _ => {}
741 }
742 }
743 }
744 }
745
746 fn constrain_callee(rcx: &mut Rcx,
747 callee_id: ast::NodeId,
748 call_expr: &ast::Expr,
749 callee_expr: &ast::Expr) {
750 let call_region = ty::ReScope(call_expr.id);
751
752 let callee_ty = rcx.resolve_node_type(callee_id);
753 match ty::get(callee_ty).sty {
754 ty::ty_bare_fn(..) => { }
755 ty::ty_closure(ref closure_ty) => {
756 let region = match closure_ty.store {
757 ty::RegionTraitStore(r, _) => {
758 // While we're here, link the closure's region with a unique
759 // immutable borrow (gathered later in borrowck)
760 let mc = mc::MemCategorizationContext::new(rcx);
761 let expr_cmt = ignore_err!(mc.cat_expr(callee_expr));
762 link_region(rcx, callee_expr.span, call_region,
763 ty::UniqueImmBorrow, expr_cmt);
764 r
765 }
766 ty::UniqTraitStore => ty::ReStatic
767 };
768 rcx.fcx.mk_subr(true, infer::InvokeClosure(callee_expr.span),
769 call_region, region);
770 }
771 _ => {
772 // this should not happen, but it does if the program is
773 // erroneous
774 //
775 // tcx.sess.span_bug(
776 // callee_expr.span,
777 // format!("Calling non-function: {}", callee_ty.repr(tcx)));
778 }
779 }
780 }
781
782 fn constrain_call(rcx: &mut Rcx,
783 // might be expr_call, expr_method_call, or an overloaded
784 // operator
785 fn_expr_id: Option<ast::NodeId>,
786 call_expr: &ast::Expr,
787 receiver: Option<@ast::Expr>,
788 arg_exprs: &[@ast::Expr],
789 implicitly_ref_args: bool) {
790 //! Invoked on every call site (i.e., normal calls, method calls,
791 //! and overloaded operators). Constrains the regions which appear
792 //! in the type of the function. Also constrains the regions that
793 //! appear in the arguments appropriately.
794
795 let tcx = rcx.fcx.tcx();
796 debug!("constrain_call(call_expr={}, \
797 receiver={}, \
798 arg_exprs={}, \
799 implicitly_ref_args={:?})",
800 call_expr.repr(tcx),
801 receiver.repr(tcx),
802 arg_exprs.repr(tcx),
803 implicitly_ref_args);
804 let callee_ty = match fn_expr_id {
805 Some(id) => rcx.resolve_node_type(id),
806 None => rcx.resolve_method_type(MethodCall::expr(call_expr.id))
807 .expect("call should have been to a method")
808 };
809 if ty::type_is_error(callee_ty) {
810 // Bail, as function type is unknown
811 return;
812 }
813 let fn_sig = ty::ty_fn_sig(callee_ty);
814
815 // `callee_region` is the scope representing the time in which the
816 // call occurs.
817 //
818 // FIXME(#6268) to support nested method calls, should be callee_id
819 let callee_scope = call_expr.id;
820 let callee_region = ty::ReScope(callee_scope);
821
822 for &arg_expr in arg_exprs.iter() {
823 debug!("Argument");
824
825 // ensure that any regions appearing in the argument type are
826 // valid for at least the lifetime of the function:
827 constrain_regions_in_type_of_node(
828 rcx, arg_expr.id, callee_region,
829 infer::CallArg(arg_expr.span));
830
831 // unfortunately, there are two means of taking implicit
832 // references, and we need to propagate constraints as a
833 // result. modes are going away and the "DerefArgs" code
834 // should be ported to use adjustments
835 if implicitly_ref_args {
836 link_by_ref(rcx, arg_expr, callee_scope);
837 }
838 }
839
840 // as loop above, but for receiver
841 for &r in receiver.iter() {
842 debug!("Receiver");
843 constrain_regions_in_type_of_node(
844 rcx, r.id, callee_region, infer::CallRcvr(r.span));
845 if implicitly_ref_args {
846 link_by_ref(rcx, r, callee_scope);
847 }
848 }
849
850 // constrain regions that may appear in the return type to be
851 // valid for the function call:
852 constrain_regions_in_type(
853 rcx, callee_region, infer::CallReturn(call_expr.span),
854 fn_sig.output);
855 }
856
857 fn constrain_autoderefs(rcx: &mut Rcx,
858 deref_expr: &ast::Expr,
859 derefs: uint,
860 mut derefd_ty: ty::t) {
861 /*!
862 * Invoked on any auto-dereference that occurs. Checks that if
863 * this is a region pointer being dereferenced, the lifetime of
864 * the pointer includes the deref expr.
865 */
866 let r_deref_expr = ty::ReScope(deref_expr.id);
867 for i in range(0u, derefs) {
868 debug!("constrain_autoderefs(deref_expr=?, derefd_ty={}, derefs={:?}/{:?}",
869 rcx.fcx.infcx().ty_to_str(derefd_ty),
870 i, derefs);
871
872 let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
873 derefd_ty = match rcx.fcx.inh.method_map.borrow().find(&method_call) {
874 Some(method) => {
875 // Treat overloaded autoderefs as if an AutoRef adjustment
876 // was applied on the base type, as that is always the case.
877 let fn_sig = ty::ty_fn_sig(method.ty);
878 let self_ty = *fn_sig.inputs.get(0);
879 let (m, r) = match ty::get(self_ty).sty {
880 ty::ty_rptr(r, ref m) => (m.mutbl, r),
881 _ => rcx.tcx().sess.span_bug(deref_expr.span,
882 format!("bad overloaded deref type {}",
883 method.ty.repr(rcx.tcx())))
884 };
885 {
886 let mc = mc::MemCategorizationContext::new(rcx);
887 let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
888 link_region(rcx, deref_expr.span, r,
889 ty::BorrowKind::from_mutbl(m), self_cmt);
890 }
891
892 // Specialized version of constrain_call.
893 constrain_regions_in_type(rcx, r_deref_expr,
894 infer::CallRcvr(deref_expr.span),
895 self_ty);
896 constrain_regions_in_type(rcx, r_deref_expr,
897 infer::CallReturn(deref_expr.span),
898 fn_sig.output);
899 fn_sig.output
900 }
901 None => derefd_ty
902 };
903
904 match ty::get(derefd_ty).sty {
905 ty::ty_rptr(r_ptr, _) => {
906 mk_subregion_due_to_dereference(rcx, deref_expr.span,
907 r_deref_expr, r_ptr);
908 }
909 _ => {}
910 }
911
912 match ty::deref(derefd_ty, true) {
913 Some(mt) => derefd_ty = mt.ty,
914 /* if this type can't be dereferenced, then there's already an error
915 in the session saying so. Just bail out for now */
916 None => break
917 }
918 }
919 }
920
921 pub fn mk_subregion_due_to_dereference(rcx: &mut Rcx,
922 deref_span: Span,
923 minimum_lifetime: ty::Region,
924 maximum_lifetime: ty::Region) {
925 rcx.fcx.mk_subr(true, infer::DerefPointer(deref_span),
926 minimum_lifetime, maximum_lifetime)
927 }
928
929
930 fn constrain_index(rcx: &mut Rcx,
931 index_expr: &ast::Expr,
932 indexed_ty: ty::t)
933 {
934 /*!
935 * Invoked on any index expression that occurs. Checks that if
936 * this is a slice being indexed, the lifetime of the pointer
937 * includes the deref expr.
938 */
939
940 debug!("constrain_index(index_expr=?, indexed_ty={}",
941 rcx.fcx.infcx().ty_to_str(indexed_ty));
942
943 let r_index_expr = ty::ReScope(index_expr.id);
944 match ty::get(indexed_ty).sty {
945 ty::ty_rptr(r_ptr, mt) => match ty::get(mt.ty).sty {
946 ty::ty_vec(_, None) | ty::ty_str => {
947 rcx.fcx.mk_subr(true, infer::IndexSlice(index_expr.span),
948 r_index_expr, r_ptr);
949 }
950 _ => {}
951 },
952
953 _ => {}
954 }
955 }
956
957 fn constrain_regions_in_type_of_node(
958 rcx: &mut Rcx,
959 id: ast::NodeId,
960 minimum_lifetime: ty::Region,
961 origin: infer::SubregionOrigin) {
962 //! Guarantees that any lifetimes which appear in the type of
963 //! the node `id` (after applying adjustments) are valid for at
964 //! least `minimum_lifetime`
965
966 let tcx = rcx.fcx.tcx();
967
968 // Try to resolve the type. If we encounter an error, then typeck
969 // is going to fail anyway, so just stop here and let typeck
970 // report errors later on in the writeback phase.
971 let ty0 = rcx.resolve_node_type(id);
972 let ty = ty::adjust_ty(tcx, origin.span(), id, ty0,
973 rcx.fcx.inh.adjustments.borrow().find(&id),
974 |method_call| rcx.resolve_method_type(method_call));
975 debug!("constrain_regions_in_type_of_node(\
976 ty={}, ty0={}, id={}, minimum_lifetime={:?})",
977 ty_to_str(tcx, ty), ty_to_str(tcx, ty0),
978 id, minimum_lifetime);
979 constrain_regions_in_type(rcx, minimum_lifetime, origin, ty);
980 }
981
982 fn constrain_regions_in_type(
983 rcx: &mut Rcx,
984 minimum_lifetime: ty::Region,
985 origin: infer::SubregionOrigin,
986 ty: ty::t) {
987 /*!
988 * Requires that any regions which appear in `ty` must be
989 * superregions of `minimum_lifetime`. Also enforces the constraint
990 * that given a pointer type `&'r T`, T must not contain regions
991 * that outlive 'r, as well as analogous constraints for other
992 * lifetime'd types.
993 *
994 * This check prevents regions from being used outside of the block in
995 * which they are valid. Recall that regions represent blocks of
996 * code or expressions: this requirement basically says "any place
997 * that uses or may use a region R must be within the block of
998 * code that R corresponds to."
999 */
1000
1001 let tcx = rcx.fcx.ccx.tcx;
1002
1003 debug!("constrain_regions_in_type(minimum_lifetime={}, ty={})",
1004 region_to_str(tcx, "", false, minimum_lifetime),
1005 ty_to_str(tcx, ty));
1006
1007 relate_nested_regions(tcx, Some(minimum_lifetime), ty, |r_sub, r_sup| {
1008 debug!("relate_nested_regions(r_sub={}, r_sup={})",
1009 r_sub.repr(tcx),
1010 r_sup.repr(tcx));
1011
1012 if r_sup.is_bound() || r_sub.is_bound() {
1013 // a bound region is one which appears inside an fn type.
1014 // (e.g., the `&` in `fn(&T)`). Such regions need not be
1015 // constrained by `minimum_lifetime` as they are placeholders
1016 // for regions that are as-yet-unknown.
1017 } else if r_sub == minimum_lifetime {
1018 rcx.fcx.mk_subr(
1019 true, origin.clone(),
1020 r_sub, r_sup);
1021 } else {
1022 rcx.fcx.mk_subr(
1023 true, infer::ReferenceOutlivesReferent(ty, origin.span()),
1024 r_sub, r_sup);
1025 }
1026 });
1027 }
1028
1029 fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
1030 mutability: ast::Mutability, base: &ast::Expr) {
1031 /*!
1032 * Computes the guarantor for an expression `&base` and then
1033 * ensures that the lifetime of the resulting pointer is linked
1034 * to the lifetime of its guarantor (if any).
1035 */
1036
1037 debug!("link_addr_of(base=?)");
1038
1039 let cmt = {
1040 let mc = mc::MemCategorizationContext::new(rcx);
1041 ignore_err!(mc.cat_expr(base))
1042 };
1043 link_region_from_node_type(rcx, expr.span, expr.id, mutability, cmt);
1044 }
1045
1046 fn link_local(rcx: &Rcx, local: &ast::Local) {
1047 /*!
1048 * Computes the guarantors for any ref bindings in a `let` and
1049 * then ensures that the lifetime of the resulting pointer is
1050 * linked to the lifetime of the initialization expression.
1051 */
1052
1053 debug!("regionck::for_local()");
1054 let init_expr = match local.init {
1055 None => { return; }
1056 Some(expr) => expr,
1057 };
1058 let mc = mc::MemCategorizationContext::new(rcx);
1059 let discr_cmt = ignore_err!(mc.cat_expr(init_expr));
1060 link_pattern(rcx, mc, discr_cmt, local.pat);
1061 }
1062
1063 fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) {
1064 /*!
1065 * Computes the guarantors for any ref bindings in a match and
1066 * then ensures that the lifetime of the resulting pointer is
1067 * linked to the lifetime of its guarantor (if any).
1068 */
1069
1070 debug!("regionck::for_match()");
1071 let mc = mc::MemCategorizationContext::new(rcx);
1072 let discr_cmt = ignore_err!(mc.cat_expr(discr));
1073 debug!("discr_cmt={}", discr_cmt.repr(rcx.tcx()));
1074 for arm in arms.iter() {
1075 for &root_pat in arm.pats.iter() {
1076 link_pattern(rcx, mc, discr_cmt.clone(), root_pat);
1077 }
1078 }
1079 }
1080
1081 fn link_pattern(rcx: &Rcx,
1082 mc: mc::MemCategorizationContext<Rcx>,
1083 discr_cmt: mc::cmt,
1084 root_pat: &ast::Pat) {
1085 /*!
1086 * Link lifetimes of any ref bindings in `root_pat` to
1087 * the pointers found in the discriminant, if needed.
1088 */
1089
1090 let _ = mc.cat_pattern(discr_cmt, root_pat, |mc, sub_cmt, sub_pat| {
1091 match sub_pat.node {
1092 // `ref x` pattern
1093 ast::PatIdent(ast::BindByRef(mutbl), _, _) => {
1094 link_region_from_node_type(
1095 rcx, sub_pat.span, sub_pat.id,
1096 mutbl, sub_cmt);
1097 }
1098
1099 // `[_, ..slice, _]` pattern
1100 ast::PatVec(_, Some(slice_pat), _) => {
1101 match mc.cat_slice_pattern(sub_cmt, slice_pat) {
1102 Ok((slice_cmt, slice_mutbl, slice_r)) => {
1103 link_region(rcx, sub_pat.span, slice_r,
1104 ty::BorrowKind::from_mutbl(slice_mutbl),
1105 slice_cmt);
1106 }
1107 Err(()) => {}
1108 }
1109 }
1110 _ => {}
1111 }
1112 });
1113 }
1114
1115 fn link_autoref(rcx: &Rcx,
1116 expr: &ast::Expr,
1117 autoderefs: uint,
1118 autoref: &ty::AutoRef) {
1119 /*!
1120 * Link lifetime of borrowed pointer resulting from autoref
1121 * to lifetimes in the value being autoref'd.
1122 */
1123
1124 debug!("link_autoref(autoref={:?})", autoref);
1125 let mc = mc::MemCategorizationContext::new(rcx);
1126 let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
1127 debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx()));
1128
1129 match *autoref {
1130 ty::AutoPtr(r, m) => {
1131 link_region(rcx, expr.span, r,
1132 ty::BorrowKind::from_mutbl(m), expr_cmt);
1133 }
1134
1135 ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => {
1136 let cmt_index = mc.cat_index(expr, expr_cmt, autoderefs+1);
1137 link_region(rcx, expr.span, r,
1138 ty::BorrowKind::from_mutbl(m), cmt_index);
1139 }
1140
1141 ty::AutoBorrowObj(r, m) => {
1142 let cmt_deref = mc.cat_deref_obj(expr, expr_cmt);
1143 link_region(rcx, expr.span, r,
1144 ty::BorrowKind::from_mutbl(m), cmt_deref);
1145 }
1146
1147 ty::AutoUnsafe(_) => {}
1148 }
1149 }
1150
1151 fn link_by_ref(rcx: &Rcx,
1152 expr: &ast::Expr,
1153 callee_scope: ast::NodeId) {
1154 /*!
1155 * Computes the guarantor for cases where the `expr` is
1156 * being passed by implicit reference and must outlive
1157 * `callee_scope`.
1158 */
1159
1160 let tcx = rcx.tcx();
1161 debug!("link_by_ref(expr={}, callee_scope={})",
1162 expr.repr(tcx), callee_scope);
1163 let mc = mc::MemCategorizationContext::new(rcx);
1164 let expr_cmt = ignore_err!(mc.cat_expr(expr));
1165 let region_min = ty::ReScope(callee_scope);
1166 link_region(rcx, expr.span, region_min, ty::ImmBorrow, expr_cmt);
1167 }
1168
1169 fn link_region_from_node_type(rcx: &Rcx,
1170 span: Span,
1171 id: ast::NodeId,
1172 mutbl: ast::Mutability,
1173 cmt_borrowed: mc::cmt) {
1174 /*!
1175 * Like `link_region()`, except that the region is
1176 * extracted from the type of `id`, which must be some
1177 * reference (`&T`, `&str`, etc).
1178 */
1179
1180 let rptr_ty = rcx.resolve_node_type(id);
1181 if !ty::type_is_bot(rptr_ty) && !ty::type_is_error(rptr_ty) {
1182 let tcx = rcx.fcx.ccx.tcx;
1183 debug!("rptr_ty={}", ty_to_str(tcx, rptr_ty));
1184 let r = ty::ty_region(tcx, span, rptr_ty);
1185 link_region(rcx, span, r, ty::BorrowKind::from_mutbl(mutbl),
1186 cmt_borrowed);
1187 }
1188 }
1189
1190 fn link_region(rcx: &Rcx,
1191 span: Span,
1192 region_min: ty::Region,
1193 kind: ty::BorrowKind,
1194 cmt_borrowed: mc::cmt) {
1195 /*!
1196 * Informs the inference engine that a borrow of `cmt`
1197 * must have the borrow kind `kind` and lifetime `region_min`.
1198 * If `cmt` is a deref of a region pointer with
1199 * lifetime `r_borrowed`, this will add the constraint that
1200 * `region_min <= r_borrowed`.
1201 */
1202
1203 // Iterate through all the things that must be live at least
1204 // for the lifetime `region_min` for the borrow to be valid:
1205 let mut cmt_borrowed = cmt_borrowed;
1206 loop {
1207 debug!("link_region(region_min={}, kind={}, cmt_borrowed={})",
1208 region_min.repr(rcx.tcx()),
1209 kind.repr(rcx.tcx()),
1210 cmt_borrowed.repr(rcx.tcx()));
1211 match cmt_borrowed.cat.clone() {
1212 mc::cat_deref(base, _, mc::BorrowedPtr(_, r_borrowed)) => {
1213 // References to an upvar `x` are translated to
1214 // `*x`, since that is what happens in the
1215 // underlying machine. We detect such references
1216 // and treat them slightly differently, both to
1217 // offer better error messages and because we need
1218 // to infer the kind of borrow (mut, const, etc)
1219 // to use for each upvar.
1220 let cause = match base.cat {
1221 mc::cat_upvar(ref upvar_id, _) => {
1222 match rcx.fcx.inh.upvar_borrow_map.borrow_mut()
1223 .find_mut(upvar_id) {
1224 Some(upvar_borrow) => {
1225 debug!("link_region: {} <= {}",
1226 region_min.repr(rcx.tcx()),
1227 upvar_borrow.region.repr(rcx.tcx()));
1228 adjust_upvar_borrow_kind_for_loan(
1229 *upvar_id,
1230 upvar_borrow,
1231 kind);
1232 infer::ReborrowUpvar(span, *upvar_id)
1233 }
1234 None => {
1235 rcx.tcx().sess.span_bug(
1236 span,
1237 format!("Illegal upvar id: {}",
1238 upvar_id.repr(rcx.tcx())));
1239 }
1240 }
1241 }
1242
1243 _ => {
1244 infer::Reborrow(span)
1245 }
1246 };
1247
1248 debug!("link_region: {} <= {}",
1249 region_min.repr(rcx.tcx()),
1250 r_borrowed.repr(rcx.tcx()));
1251 rcx.fcx.mk_subr(true, cause, region_min, r_borrowed);
1252
1253 if kind != ty::ImmBorrow {
1254 // If this is a mutable borrow, then the thing
1255 // being borrowed will have to be unique.
1256 // In user code, this means it must be an `&mut`
1257 // borrow, but for an upvar, we might opt
1258 // for an immutable-unique borrow.
1259 adjust_upvar_borrow_kind_for_unique(rcx, base);
1260 }
1261
1262 // Borrowing an `&mut` pointee for `region_min` is
1263 // only valid if the pointer resides in a unique
1264 // location which is itself valid for
1265 // `region_min`. We don't care about the unique
1266 // part, but we may need to influence the
1267 // inference to ensure that the location remains
1268 // valid.
1269 //
1270 // FIXME(#8624) fixing borrowck will require this
1271 // if m == ast::m_mutbl {
1272 // cmt_borrowed = cmt_base;
1273 // } else {
1274 // return;
1275 // }
1276 return;
1277 }
1278 mc::cat_discr(cmt_base, _) |
1279 mc::cat_downcast(cmt_base) |
1280 mc::cat_deref(cmt_base, _, mc::GcPtr(..)) |
1281 mc::cat_deref(cmt_base, _, mc::OwnedPtr) |
1282 mc::cat_interior(cmt_base, _) => {
1283 // Interior or owned data requires its base to be valid
1284 cmt_borrowed = cmt_base;
1285 }
1286 mc::cat_deref(_, _, mc::UnsafePtr(..)) |
1287 mc::cat_static_item |
1288 mc::cat_copied_upvar(..) |
1289 mc::cat_local(..) |
1290 mc::cat_arg(..) |
1291 mc::cat_upvar(..) |
1292 mc::cat_rvalue(..) => {
1293 // These are all "base cases" with independent lifetimes
1294 // that are not subject to inference
1295 return;
1296 }
1297 }
1298 }
1299 }
1300
1301 fn adjust_borrow_kind_for_assignment_lhs(rcx: &Rcx,
1302 lhs: &ast::Expr) {
1303 /*!
1304 * Adjusts the inferred borrow_kind as needed to account
1305 * for upvars that are assigned to in an assignment
1306 * expression.
1307 */
1308
1309 let mc = mc::MemCategorizationContext::new(rcx);
1310 let cmt = ignore_err!(mc.cat_expr(lhs));
1311 adjust_upvar_borrow_kind_for_mut(rcx, cmt);
1312 }
1313
1314 fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx,
1315 cmt: mc::cmt) {
1316 let mut cmt = cmt;
1317 loop {
1318 debug!("adjust_upvar_borrow_kind_for_mut(cmt={})",
1319 cmt.repr(rcx.tcx()));
1320
1321 match cmt.cat.clone() {
1322 mc::cat_deref(base, _, mc::OwnedPtr) |
1323 mc::cat_interior(base, _) |
1324 mc::cat_downcast(base) |
1325 mc::cat_discr(base, _) => {
1326 // Interior or owned data is mutable if base is
1327 // mutable, so iterate to the base.
1328 cmt = base;
1329 continue;
1330 }
1331
1332 mc::cat_deref(base, _, mc::BorrowedPtr(..)) => {
1333 match base.cat {
1334 mc::cat_upvar(ref upvar_id, _) => {
1335 // if this is an implicit deref of an
1336 // upvar, then we need to modify the
1337 // borrow_kind of the upvar to make sure it
1338 // is inferred to mutable if necessary
1339 let mut upvar_borrow_map =
1340 rcx.fcx.inh.upvar_borrow_map.borrow_mut();
1341 let ub = upvar_borrow_map.get_mut(upvar_id);
1342 return adjust_upvar_borrow_kind(*upvar_id, ub, ty::MutBorrow);
1343 }
1344
1345 _ => {}
1346 }
1347
1348 // assignment to deref of an `&mut`
1349 // borrowed pointer implies that the
1350 // pointer itself must be unique, but not
1351 // necessarily *mutable*
1352 return adjust_upvar_borrow_kind_for_unique(rcx, base);
1353 }
1354
1355 mc::cat_deref(_, _, mc::UnsafePtr(..)) |
1356 mc::cat_deref(_, _, mc::GcPtr) |
1357 mc::cat_static_item |
1358 mc::cat_rvalue(_) |
1359 mc::cat_copied_upvar(_) |
1360 mc::cat_local(_) |
1361 mc::cat_arg(_) |
1362 mc::cat_upvar(..) => {
1363 return;
1364 }
1365 }
1366 }
1367 }
1368
1369 fn adjust_upvar_borrow_kind_for_unique(rcx: &Rcx, cmt: mc::cmt) {
1370 let mut cmt = cmt;
1371 loop {
1372 debug!("adjust_upvar_borrow_kind_for_unique(cmt={})",
1373 cmt.repr(rcx.tcx()));
1374
1375 match cmt.cat.clone() {
1376 mc::cat_deref(base, _, mc::OwnedPtr) |
1377 mc::cat_interior(base, _) |
1378 mc::cat_downcast(base) |
1379 mc::cat_discr(base, _) => {
1380 // Interior or owned data is unique if base is
1381 // unique.
1382 cmt = base;
1383 continue;
1384 }
1385
1386 mc::cat_deref(base, _, mc::BorrowedPtr(..)) => {
1387 match base.cat {
1388 mc::cat_upvar(ref upvar_id, _) => {
1389 // if this is an implicit deref of an
1390 // upvar, then we need to modify the
1391 // borrow_kind of the upvar to make sure it
1392 // is inferred to unique if necessary
1393 let mut ub = rcx.fcx.inh.upvar_borrow_map.borrow_mut();
1394 let ub = ub.get_mut(upvar_id);
1395 return adjust_upvar_borrow_kind(*upvar_id, ub, ty::UniqueImmBorrow);
1396 }
1397
1398 _ => {}
1399 }
1400
1401 // for a borrowed pointer to be unique, its
1402 // base must be unique
1403 return adjust_upvar_borrow_kind_for_unique(rcx, base);
1404 }
1405
1406 mc::cat_deref(_, _, mc::UnsafePtr(..)) |
1407 mc::cat_deref(_, _, mc::GcPtr) |
1408 mc::cat_static_item |
1409 mc::cat_rvalue(_) |
1410 mc::cat_copied_upvar(_) |
1411 mc::cat_local(_) |
1412 mc::cat_arg(_) |
1413 mc::cat_upvar(..) => {
1414 return;
1415 }
1416 }
1417 }
1418 }
1419
1420 fn link_upvar_borrow_kind_for_nested_closures(rcx: &mut Rcx,
1421 inner_upvar_id: ty::UpvarId,
1422 outer_upvar_id: ty::UpvarId) {
1423 /*!
1424 * Indicates that the borrow_kind of `outer_upvar_id` must
1425 * permit a reborrowing with the borrow_kind of `inner_upvar_id`.
1426 * This occurs in nested closures, see comment above at the call to
1427 * this function.
1428 */
1429
1430 debug!("link_upvar_borrow_kind: inner_upvar_id={:?} outer_upvar_id={:?}",
1431 inner_upvar_id, outer_upvar_id);
1432
1433 let mut upvar_borrow_map = rcx.fcx.inh.upvar_borrow_map.borrow_mut();
1434 let inner_borrow = upvar_borrow_map.get_copy(&inner_upvar_id);
1435 match upvar_borrow_map.find_mut(&outer_upvar_id) {
1436 Some(outer_borrow) => {
1437 adjust_upvar_borrow_kind(outer_upvar_id, outer_borrow, inner_borrow.kind);
1438 }
1439 None => { /* outer closure is not a stack closure */ }
1440 }
1441 }
1442
1443 fn adjust_upvar_borrow_kind_for_loan(upvar_id: ty::UpvarId,
1444 upvar_borrow: &mut ty::UpvarBorrow,
1445 kind: ty::BorrowKind) {
1446 debug!("adjust_upvar_borrow_kind_for_loan: upvar_id={:?} kind={:?} -> {:?}",
1447 upvar_id, upvar_borrow.kind, kind);
1448
1449 adjust_upvar_borrow_kind(upvar_id, upvar_borrow, kind)
1450 }
1451
1452 fn adjust_upvar_borrow_kind(upvar_id: ty::UpvarId,
1453 upvar_borrow: &mut ty::UpvarBorrow,
1454 kind: ty::BorrowKind) {
1455 /*!
1456 * We infer the borrow_kind with which to borrow upvars in a stack
1457 * closure. The borrow_kind basically follows a lattice of
1458 * `imm < unique-imm < mut`, moving from left to right as needed (but never
1459 * right to left). Here the argument `mutbl` is the borrow_kind that
1460 * is required by some particular use.
1461 */
1462
1463 debug!("adjust_upvar_borrow_kind: id={:?} kind=({:?} -> {:?})",
1464 upvar_id, upvar_borrow.kind, kind);
1465
1466 match (upvar_borrow.kind, kind) {
1467 // Take RHS:
1468 (ty::ImmBorrow, ty::UniqueImmBorrow) |
1469 (ty::ImmBorrow, ty::MutBorrow) |
1470 (ty::UniqueImmBorrow, ty::MutBorrow) => {
1471 upvar_borrow.kind = kind;
1472 }
1473 // Take LHS:
1474 (ty::ImmBorrow, ty::ImmBorrow) |
1475 (ty::UniqueImmBorrow, ty::ImmBorrow) |
1476 (ty::UniqueImmBorrow, ty::UniqueImmBorrow) |
1477 (ty::MutBorrow, _) => {
1478 }
1479 }
1480 }
librustc/middle/typeck/check/regionck.rs:781:1-781:1 -fn- definition:
fn constrain_call(rcx: &mut Rcx,
// might be expr_call, expr_method_call, or an overloaded
// operator
references:- 6457: ast::ExprMethodCall(_, _, ref args) => {
458: constrain_call(rcx, None, expr, Some(*args.get(0)),
459: args.slice_from(1), false);
--
501: Some(method) => {
502: constrain_call(rcx, None, expr, Some(base), [], true);
503: ty::ty_fn_ret(method.ty)
librustc/middle/typeck/check/regionck.rs:158:1-158:1 -struct- definition:
pub struct Rcx<'a> {
fcx: &'a FnCtxt<'a>,
// id of innermost fn or loop
references:- 34librustc/middle/typeck/check/regionck.rs:1189:1-1189:1 -fn- definition:
fn link_region(rcx: &Rcx,
span: Span,
region_min: ty::Region,
references:- 81136: let cmt_index = mc.cat_index(expr, expr_cmt, autoderefs+1);
1137: link_region(rcx, expr.span, r,
1138: ty::BorrowKind::from_mutbl(m), cmt_index);
--
1184: let r = ty::ty_region(tcx, span, rptr_ty);
1185: link_region(rcx, span, r, ty::BorrowKind::from_mutbl(mutbl),
1186: cmt_borrowed);
librustc/middle/typeck/check/regionck.rs:1451:1-1451:1 -fn- definition:
fn adjust_upvar_borrow_kind(upvar_id: ty::UpvarId,
upvar_borrow: &mut ty::UpvarBorrow,
kind: ty::BorrowKind) {
references:- 41436: Some(outer_borrow) => {
1437: adjust_upvar_borrow_kind(outer_upvar_id, outer_borrow, inner_borrow.kind);
1438: }
--
1449: adjust_upvar_borrow_kind(upvar_id, upvar_borrow, kind)
1450: }
librustc/middle/typeck/check/regionck.rs:1368:1-1368:1 -fn- definition:
fn adjust_upvar_borrow_kind_for_unique(rcx: &Rcx, cmt: mc::cmt) {
let mut cmt = cmt;
loop {
references:- 31402: // base must be unique
1403: return adjust_upvar_borrow_kind_for_unique(rcx, base);
1404: }
librustc/middle/typeck/check/regionck.rs:1150:1-1150:1 -fn- definition:
fn link_by_ref(rcx: &Rcx,
expr: &ast::Expr,
callee_scope: ast::NodeId) {
references:- 2835: if implicitly_ref_args {
836: link_by_ref(rcx, arg_expr, callee_scope);
837: }
--
845: if implicitly_ref_args {
846: link_by_ref(rcx, r, callee_scope);
847: }
librustc/middle/typeck/check/regionck.rs:165:1-165:1 -fn- definition:
fn region_of_def(fcx: &FnCtxt, def: ast::Def) -> ty::Region {
/*!
* Returns the validity region of `def` -- that is, how long
references:- 2688: // Guarantee that the closure does not outlive the variable itself.
689: let en_region = region_of_def(rcx.fcx, def);
690: debug!("en_region = {}", en_region.repr(tcx));
librustc/middle/typeck/check/regionck.rs:1080:1-1080:1 -fn- definition:
fn link_pattern(rcx: &Rcx,
mc: mc::MemCategorizationContext<Rcx>,
discr_cmt: mc::cmt,
references:- 21059: let discr_cmt = ignore_err!(mc.cat_expr(init_expr));
1060: link_pattern(rcx, mc, discr_cmt, local.pat);
1061: }
--
1075: for &root_pat in arm.pats.iter() {
1076: link_pattern(rcx, mc, discr_cmt.clone(), root_pat);
1077: }
librustc/middle/typeck/check/regionck.rs:920:1-920:1 -fn- definition:
pub fn mk_subregion_due_to_dereference(rcx: &mut Rcx,
deref_span: Span,
minimum_lifetime: ty::Region,
references:- 2905: ty::ty_rptr(r_ptr, _) => {
906: mk_subregion_due_to_dereference(rcx, deref_expr.span,
907: r_deref_expr, r_ptr);
librustc/middle/typeck/check/regionck.rs:1168:1-1168:1 -fn- definition:
fn link_region_from_node_type(rcx: &Rcx,
span: Span,
id: ast::NodeId,
references:- 21093: ast::PatIdent(ast::BindByRef(mutbl), _, _) => {
1094: link_region_from_node_type(
1095: rcx, sub_pat.span, sub_pat.id,
librustc/middle/typeck/check/regionck.rs:981:1-981:1 -fn- definition:
fn constrain_regions_in_type(
rcx: &mut Rcx,
minimum_lifetime: ty::Region,
references:- 7545: let source_ty = rcx.resolve_expr_type_adjusted(source);
546: constrain_regions_in_type(
547: rcx,
--
851: // valid for the function call:
852: constrain_regions_in_type(
853: rcx, callee_region, infer::CallReturn(call_expr.span),
--
892: // Specialized version of constrain_call.
893: constrain_regions_in_type(rcx, r_deref_expr,
894: infer::CallRcvr(deref_expr.span),
--
978: id, minimum_lifetime);
979: constrain_regions_in_type(rcx, minimum_lifetime, origin, ty);
980: }
librustc/middle/typeck/check/regionck.rs:360:1-360:1 -fn- definition:
fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) {
let tcx = rcx.fcx.tcx();
debug!("regionck::visit_pat(pat={})", pat.repr(tcx));
references:- 2347: for &p in arm.pats.iter() {
348: constrain_bindings_in_pat(p, rcx);
349: }
--
355: // see above
356: constrain_bindings_in_pat(l.pat, rcx);
357: link_local(rcx, l);
librustc/middle/typeck/check/regionck.rs:956:1-956:1 -fn- definition:
fn constrain_regions_in_type_of_node(
rcx: &mut Rcx,
id: ast::NodeId,
references:- 4388: let var_region = tcx.region_maps.var_region(id);
389: constrain_regions_in_type_of_node(
390: rcx, id, var_region,
--
826: // valid for at least the lifetime of the function:
827: constrain_regions_in_type_of_node(
828: rcx, arg_expr.id, callee_region,
--
842: debug!("Receiver");
843: constrain_regions_in_type_of_node(
844: rcx, r.id, callee_region, infer::CallRcvr(r.span));
librustc/middle/typeck/check/regionck.rs:1300:1-1300:1 -fn- definition:
fn adjust_borrow_kind_for_assignment_lhs(rcx: &Rcx,
lhs: &ast::Expr) {
/*!
references:- 2474: adjust_borrow_kind_for_assignment_lhs(rcx, lhs);