@@ -351,6 +351,9 @@ pub struct ctxt_ {
351
351
// is used for lazy resolution of traits.
352
352
populated_external_traits : RefCell < HashSet < ast:: DefId > > ,
353
353
354
+ // Borrows
355
+ upvar_borrow_map : RefCell < UpvarBorrowMap > ,
356
+
354
357
// These two caches are used by const_eval when decoding external statics
355
358
// and variants that are found.
356
359
extern_const_statics : RefCell < HashMap < ast:: DefId , Option < @ast:: Expr > > > ,
@@ -494,6 +497,120 @@ pub enum Region {
494
497
ReEmpty ,
495
498
}
496
499
500
+ /**
501
+ * Upvars do not get their own node-id. Instead, we use the pair of
502
+ * the original var id (that is, the root variable that is referenced
503
+ * by the upvar) and the id of the closure expression.
504
+ */
505
+ #[ deriving( Clone , Eq , IterBytes ) ]
506
+ pub struct UpvarId {
507
+ var_id : ast:: NodeId ,
508
+ closure_expr_id : ast:: NodeId ,
509
+ }
510
+
511
+ #[ deriving( Clone , Eq , IterBytes ) ]
512
+ pub enum BorrowKind {
513
+ /// Data must be immutable and is aliasable.
514
+ ImmBorrow ,
515
+
516
+ /// Data must be immutable but not aliasable. This kind of borrow
517
+ /// cannot currently be expressed by the user and is used only in
518
+ /// implicit closure bindings. It is needed when you the closure
519
+ /// is borrowing or mutating a mutable referent, e.g.:
520
+ ///
521
+ /// let x: &mut int = ...;
522
+ /// let y = || *x += 5;
523
+ ///
524
+ /// If we were to try to translate this closure into a more explicit
525
+ /// form, we'd encounter an error with the code as written:
526
+ ///
527
+ /// struct Env { x: & &mut int }
528
+ /// let x: &mut int = ...;
529
+ /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn
530
+ /// fn fn_ptr(env: &mut Env) { **env.x += 5; }
531
+ ///
532
+ /// This is then illegal because you cannot mutate a `&mut` found
533
+ /// in an aliasable location. To solve, you'd have to translate with
534
+ /// an `&mut` borrow:
535
+ ///
536
+ /// struct Env { x: & &mut int }
537
+ /// let x: &mut int = ...;
538
+ /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x
539
+ /// fn fn_ptr(env: &mut Env) { **env.x += 5; }
540
+ ///
541
+ /// Now the assignment to `**env.x` is legal, but creating a
542
+ /// mutable pointer to `x` is not because `x` is not mutable. We
543
+ /// could fix this by declaring `x` as `let mut x`. This is ok in
544
+ /// user code, if awkward, but extra weird for closures, since the
545
+ /// borrow is hidden.
546
+ ///
547
+ /// So we introduce a "unique imm" borrow -- the referent is
548
+ /// immutable, but not aliasable. This solves the problem. For
549
+ /// simplicity, we don't give users the way to express this
550
+ /// borrow, it's just used when translating closures.
551
+ UniqueImmBorrow ,
552
+
553
+ /// Data is mutable and not aliasable.
554
+ MutBorrow
555
+ }
556
+
557
+ /**
558
+ * Information describing the borrowing of an upvar. This is computed
559
+ * during `typeck`, specifically by `regionck`. The general idea is
560
+ * that the compiler analyses treat closures like:
561
+ *
562
+ * let closure: &'e fn() = || {
563
+ * x = 1; // upvar x is assigned to
564
+ * use(y); // upvar y is read
565
+ * foo(&z); // upvar z is borrowed immutably
566
+ * };
567
+ *
568
+ * as if they were "desugared" to something loosely like:
569
+ *
570
+ * struct Vars<'x,'y,'z> { x: &'x mut int,
571
+ * y: &'y const int,
572
+ * z: &'z int }
573
+ * let closure: &'e fn() = {
574
+ * fn f(env: &Vars) {
575
+ * *env.x = 1;
576
+ * use(*env.y);
577
+ * foo(env.z);
578
+ * }
579
+ * let env: &'e mut Vars<'x,'y,'z> = &mut Vars { x: &'x mut x,
580
+ * y: &'y const y,
581
+ * z: &'z z };
582
+ * (env, f)
583
+ * };
584
+ *
585
+ * This is basically what happens at runtime. The closure is basically
586
+ * an existentially quantified version of the `(env, f)` pair.
587
+ *
588
+ * This data structure indicates the region and mutability of a single
589
+ * one of the `x...z` borrows.
590
+ *
591
+ * It may not be obvious why each borrowed variable gets its own
592
+ * lifetime (in the desugared version of the example, these are indicated
593
+ * by the lifetime parameters `'x`, `'y`, and `'z` in the `Vars` definition).
594
+ * Each such lifetime must encompass the lifetime `'e` of the closure itself,
595
+ * but need not be identical to it. The reason that this makes sense:
596
+ *
597
+ * - Callers are only permitted to invoke the closure, and hence to
598
+ * use the pointers, within the lifetime `'e`, so clearly `'e` must
599
+ * be a sublifetime of `'x...'z`.
600
+ * - The closure creator knows which upvars were borrowed by the closure
601
+ * and thus `x...z` will be reserved for `'x...'z` respectively.
602
+ * - Through mutation, the borrowed upvars can actually escape the
603
+ * the closure, so sometimes it is necessary for them to be larger
604
+ * than the closure lifetime itself.
605
+ */
606
+ #[ deriving( Eq , Clone ) ]
607
+ pub struct UpvarBorrow {
608
+ kind : BorrowKind ,
609
+ region : ty:: Region ,
610
+ }
611
+
612
+ pub type UpvarBorrowMap = HashMap < UpvarId , UpvarBorrow > ;
613
+
497
614
impl Region {
498
615
pub fn is_bound ( & self ) -> bool {
499
616
match self {
@@ -999,7 +1116,7 @@ pub fn mk_ctxt(s: session::Session,
999
1116
impl_vtables : RefCell :: new ( HashMap :: new ( ) ) ,
1000
1117
populated_external_types : RefCell :: new ( HashSet :: new ( ) ) ,
1001
1118
populated_external_traits : RefCell :: new ( HashSet :: new ( ) ) ,
1002
-
1119
+ upvar_borrow_map : RefCell :: new ( HashMap :: new ( ) ) ,
1003
1120
extern_const_statics : RefCell :: new ( HashMap :: new ( ) ) ,
1004
1121
extern_const_variants : RefCell :: new ( HashMap :: new ( ) ) ,
1005
1122
}
@@ -5100,3 +5217,28 @@ impl substs {
5100
5217
}
5101
5218
}
5102
5219
}
5220
+
5221
+ impl BorrowKind {
5222
+ pub fn from_mutbl ( m : ast:: Mutability ) -> BorrowKind {
5223
+ match m {
5224
+ ast:: MutMutable => MutBorrow ,
5225
+ ast:: MutImmutable => ImmBorrow ,
5226
+ }
5227
+ }
5228
+
5229
+ pub fn to_user_str ( & self ) -> & ' static str {
5230
+ match * self {
5231
+ MutBorrow => "mutable" ,
5232
+ ImmBorrow => "immutable" ,
5233
+ UniqueImmBorrow => "uniquely immutable" ,
5234
+ }
5235
+ }
5236
+
5237
+ pub fn to_short_str ( & self ) -> & ' static str {
5238
+ match * self {
5239
+ MutBorrow => "mut" ,
5240
+ ImmBorrow => "imm" ,
5241
+ UniqueImmBorrow => "own" ,
5242
+ }
5243
+ }
5244
+ }
0 commit comments