@@ -74,8 +74,7 @@ import rscope::{anon_rscope, binding_rscope, empty_rscope, in_anon_rscope};
74
74
import rscope :: { in_binding_rscope, region_scope, type_rscope} ;
75
75
import syntax:: ast:: ty_i;
76
76
import typeck:: infer:: { unify_methods} ; // infcx.set()
77
- import typeck:: infer:: { force_level, force_none, force_ty_vars_only,
78
- force_all} ;
77
+ import typeck:: infer:: { resolve_type, force_tvar} ;
79
78
80
79
type fn_ctxt =
81
80
// var_bindings, locals and next_var_id are shared
@@ -89,7 +88,22 @@ type fn_ctxt =
89
88
infcx : infer:: infer_ctxt ,
90
89
locals : hashmap < ast:: node_id , tv_vid > ,
91
90
92
- mut blocks : ~[ ast:: node_id ] , // stack of blocks in scope, may be empty
91
+ // Sometimes we generate region pointers where the precise region
92
+ // to use is not known. For example, an expression like `&x.f`
93
+ // where `x` is of type `@T`: in this case, we will be rooting
94
+ // `x` onto the stack frame, and we could choose to root it until
95
+ // the end of (almost) any enclosing block or expression. We
96
+ // want to pick the narrowest block that encompasses all uses.
97
+ //
98
+ // What we do in such cases is to generate a region variable and
99
+ // assign it the following two fields as bounds. The lower bound
100
+ // is always the innermost enclosing expression. The upper bound
101
+ // is the outermost enclosing expression that we could legally
102
+ // use. In practice, this is the innermost loop or function
103
+ // body.
104
+ mut region_lb : ast:: node_id ,
105
+ mut region_ub : ast:: node_id ,
106
+
93
107
in_scope_regions : isr_alist ,
94
108
95
109
node_types : smallintmap:: smallintmap < ty:: t > ,
@@ -98,7 +112,8 @@ type fn_ctxt =
98
112
ccx : @crate_ctxt } ;
99
113
100
114
// Used by check_const and check_enum_variants
101
- fn blank_fn_ctxt ( ccx : @crate_ctxt , rty : ty:: t ) -> @fn_ctxt {
115
+ fn blank_fn_ctxt ( ccx : @crate_ctxt , rty : ty:: t ,
116
+ region_bnd : ast:: node_id ) -> @fn_ctxt {
102
117
// It's kind of a kludge to manufacture a fake function context
103
118
// and statement context, but we might as well do write the code only once
104
119
@{ self_ty: none,
@@ -107,7 +122,8 @@ fn blank_fn_ctxt(ccx: @crate_ctxt, rty: ty::t) -> @fn_ctxt {
107
122
purity: ast:: pure_fn,
108
123
infcx: infer:: new_infer_ctxt ( ccx. tcx ) ,
109
124
locals: int_hash ( ) ,
110
- mut blocks: ~[ ] ,
125
+ mut region_lb: region_bnd,
126
+ mut region_ub: region_bnd,
111
127
in_scope_regions: @nil,
112
128
node_types: smallintmap:: mk ( ) ,
113
129
node_type_substs: map:: int_hash ( ) ,
@@ -217,7 +233,8 @@ fn check_fn(ccx: @crate_ctxt,
217
233
purity: purity,
218
234
infcx: infcx,
219
235
locals: locals,
220
- mut blocks: ~[ ] ,
236
+ mut region_lb: body. node . id ,
237
+ mut region_ub: body. node . id ,
221
238
in_scope_regions: isr,
222
239
node_types: node_types,
223
240
node_type_substs: node_type_substs,
@@ -307,9 +324,12 @@ fn check_fn(ccx: @crate_ctxt,
307
324
} ;
308
325
309
326
let visit_block = fn @( b: ast:: blk, & & e : ( ) , v: visit:: vt<( ) >) {
310
- vec:: push ( fcx. blocks , b. node . id ) ;
311
- visit:: visit_block ( b, e, v) ;
312
- vec:: pop ( fcx. blocks ) ;
327
+ // non-obvious: the `blk` variable maps to region lb, so
328
+ // we have to keep this up-to-date. This
329
+ // is... unfortunate. It'd be nice to not need this.
330
+ do fcx. with_region_lb ( b. node . id ) {
331
+ visit:: visit_block ( b, e, v) ;
332
+ }
313
333
} ;
314
334
315
335
// Don't descend into fns and items
@@ -430,7 +450,7 @@ impl of ast_conv for @fn_ctxt {
430
450
431
451
impl of region_scope for @fn_ctxt {
432
452
fn anon_region ( ) -> result < ty:: region , ~str > {
433
- result:: ok ( self . infcx . next_region_var ( ) )
453
+ result:: ok ( self . infcx . next_region_var_nb ( ) )
434
454
}
435
455
fn named_region ( id : ast:: ident ) -> result < ty:: region , ~str > {
436
456
do empty_rscope. named_region ( id) . chain_err |_e| {
@@ -448,10 +468,7 @@ impl of region_scope for @fn_ctxt {
448
468
impl methods for @fn_ctxt {
449
469
fn tag ( ) -> ~str { #fmt[ "%x" , ptr:: addr_of ( * self ) as uint ] }
450
470
fn block_region ( ) -> result < ty:: region , ~str > {
451
- alt vec:: last_opt ( self . blocks ) {
452
- some ( bid) { result:: ok ( ty:: re_scope ( bid) ) }
453
- none { result : : err ( ~"no block is in scope here") }
454
- }
471
+ result:: ok ( ty:: re_scope ( self . region_lb ) )
455
472
}
456
473
#[ inline( always) ]
457
474
fn write_ty ( node_id : ast:: node_id , ty : ty:: t ) {
@@ -534,15 +551,17 @@ impl methods for @fn_ctxt {
534
551
infer:: can_mk_subty ( self . infcx , sub, sup)
535
552
}
536
553
537
- fn mk_assignty ( expr : @ast:: expr , borrow_scope : ast:: node_id ,
554
+ fn mk_assignty ( expr : @ast:: expr , borrow_lb : ast:: node_id ,
538
555
sub : ty:: t , sup : ty:: t ) -> result < ( ) , ty:: type_err > {
539
- let anmnt = { expr_id: expr. id , borrow_scope: borrow_scope} ;
556
+ let anmnt = { expr_id: expr. id , borrow_lb: borrow_lb,
557
+ borrow_ub: self . region_ub } ;
540
558
infer:: mk_assignty ( self . infcx , anmnt, sub, sup)
541
559
}
542
560
543
- fn can_mk_assignty ( expr : @ast:: expr , borrow_scope : ast:: node_id ,
561
+ fn can_mk_assignty ( expr : @ast:: expr , borrow_lb : ast:: node_id ,
544
562
sub : ty:: t , sup : ty:: t ) -> result < ( ) , ty:: type_err > {
545
- let anmnt = { expr_id: expr. id , borrow_scope: borrow_scope} ;
563
+ let anmnt = { expr_id: expr. id , borrow_lb: borrow_lb,
564
+ borrow_ub: self . region_ub } ;
546
565
infer:: can_mk_assignty ( self . infcx , anmnt, sub, sup)
547
566
}
548
567
@@ -564,6 +583,20 @@ impl methods for @fn_ctxt {
564
583
}
565
584
}
566
585
}
586
+ fn with_region_lb < R > ( lb : ast:: node_id , f : fn ( ) -> R ) -> R {
587
+ let old_region_lb = self . region_lb ;
588
+ self . region_lb = lb;
589
+ let v <- f ( ) ;
590
+ self . region_lb = old_region_lb;
591
+ ret v;
592
+ }
593
+ fn with_region_ub < R > ( ub : ast:: node_id , f : fn ( ) -> R ) -> R {
594
+ let old_region_ub = self . region_ub ;
595
+ self . region_ub = ub;
596
+ let v <- f ( ) ;
597
+ self . region_ub = old_region_ub;
598
+ ret v;
599
+ }
567
600
}
568
601
569
602
fn do_autoderef ( fcx : @fn_ctxt , sp : span , t : ty:: t ) -> ty:: t {
@@ -682,7 +715,7 @@ fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id) -> ty_param_substs_and_ty {
682
715
raw_ty: ity. ty }
683
716
} ;
684
717
685
- let self_r = if rp { some ( fcx. infcx . next_region_var ( ) ) } else { none} ;
718
+ let self_r = if rp { some ( fcx. infcx . next_region_var_nb ( ) ) } else { none} ;
686
719
let tps = fcx. infcx . next_ty_vars ( n_tps) ;
687
720
688
721
let substs = { self_r: self_r, self_ty: none, tps: tps} ;
@@ -733,7 +766,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
733
766
sty @ ty:: ty_fn ( fn_ty) {
734
767
replace_bound_regions_in_fn_ty (
735
768
fcx. ccx . tcx , @nil, none, fn_ty,
736
- |_br| fcx. infcx . next_region_var ( ) ) . fn_ty
769
+ |_br| fcx. infcx . next_region_var_nb ( ) ) . fn_ty
737
770
}
738
771
sty {
739
772
// I would like to make this span_err, but it's
@@ -1017,7 +1050,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
1017
1050
-> option < O > {
1018
1051
alt expected {
1019
1052
some( t) {
1020
- alt infer :: resolve_shallow ( fcx. infcx , t, force_none ) {
1053
+ alt resolve_type ( fcx. infcx , t, force_tvar ) {
1021
1054
result:: ok ( t) { unpack ( ty:: get ( t) . struct ) }
1022
1055
_ { none }
1023
1056
}
@@ -1119,9 +1152,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
1119
1152
1120
1153
// this will be the call or block that immediately
1121
1154
// encloses the method call
1122
- let borrow_scope = fcx. tcx ( ) . region_map . get ( expr. id ) ;
1155
+ let borrow_lb = fcx. tcx ( ) . region_map . get ( expr. id ) ;
1123
1156
1124
- let lkup = method:: lookup ( fcx, expr, base, borrow_scope ,
1157
+ let lkup = method:: lookup ( fcx, expr, base, borrow_lb ,
1125
1158
expr. id , field, expr_t, tps,
1126
1159
is_self_ref) ;
1127
1160
alt lkup. method ( ) {
@@ -1364,13 +1397,17 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
1364
1397
}
1365
1398
ast:: expr_while ( cond, body) {
1366
1399
bot = check_expr_with ( fcx, cond, ty:: mk_bool ( tcx) ) ;
1367
- check_block_no_value ( fcx, body) ;
1400
+ do fcx. with_region_ub ( body. node . id ) {
1401
+ check_block_no_value ( fcx, body) ;
1402
+ }
1368
1403
fcx. write_ty ( id, ty:: mk_nil ( tcx) ) ;
1369
1404
}
1370
1405
ast:: expr_loop ( body) {
1371
- check_block_no_value ( fcx, body) ;
1372
- fcx. write_ty ( id, ty:: mk_nil ( tcx) ) ;
1373
- bot = !may_break ( body) ;
1406
+ do fcx. with_region_ub ( body. node . id ) {
1407
+ check_block_no_value ( fcx, body) ;
1408
+ }
1409
+ fcx. write_ty ( id, ty:: mk_nil ( tcx) ) ;
1410
+ bot = !may_break ( body) ;
1374
1411
}
1375
1412
ast:: expr_alt ( discrim, arms, _) {
1376
1413
bot = alt:: check_alt ( fcx, expr, discrim, arms) ;
@@ -1754,44 +1791,44 @@ fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool {
1754
1791
ast:: unsafe_blk { @{ purity : ast:: unsafe_fn with * fcx0} }
1755
1792
ast:: default_blk { fcx0 }
1756
1793
} ;
1757
- vec:: push ( fcx. blocks , blk. node . id ) ;
1758
- let mut bot = false ;
1759
- let mut warned = false ;
1760
- for blk. node. stmts. each |s| {
1761
- if bot && !warned &&
1762
- alt s. node {
1763
- ast:: stmt_decl ( @{ node: ast:: decl_local ( _) , _} , _) |
1764
- ast:: stmt_expr ( _, _) | ast:: stmt_semi ( _, _) {
1765
- true
1766
- }
1767
- _ { false }
1768
- } {
1769
- fcx. ccx . tcx . sess . span_warn ( s. span , ~"unreachable statement") ;
1770
- warned = true ;
1794
+ do fcx. with_region_lb ( blk. node . id ) {
1795
+ let mut bot = false ;
1796
+ let mut warned = false ;
1797
+ for blk. node. stmts. each |s| {
1798
+ if bot && !warned &&
1799
+ alt s. node {
1800
+ ast:: stmt_decl ( @{ node: ast:: decl_local ( _) , _} , _) |
1801
+ ast:: stmt_expr ( _, _) | ast:: stmt_semi ( _, _) {
1802
+ true
1803
+ }
1804
+ _ { false }
1805
+ } {
1806
+ fcx. ccx . tcx . sess . span_warn ( s. span , ~"unreachable statement") ;
1807
+ warned = true ;
1808
+ }
1809
+ bot |= check_stmt ( fcx, s) ;
1771
1810
}
1772
- bot |= check_stmt ( fcx, s) ;
1773
- }
1774
- alt blk. node . expr {
1775
- none { fcx. write_nil ( blk. node . id ) ; }
1776
- some ( e) {
1777
- if bot && !warned {
1778
- fcx. ccx . tcx . sess . span_warn ( e. span , ~"unreachable expression") ;
1811
+ alt blk. node . expr {
1812
+ none { fcx. write_nil ( blk. node . id ) ; }
1813
+ some ( e) {
1814
+ if bot && !warned {
1815
+ fcx. ccx . tcx . sess . span_warn ( e. span , ~"unreachable expression") ;
1816
+ }
1817
+ bot |= check_expr ( fcx, e, none) ;
1818
+ let ety = fcx. expr_ty ( e) ;
1819
+ fcx. write_ty ( blk. node . id , ety) ;
1820
+ }
1779
1821
}
1780
- bot |= check_expr ( fcx, e, none) ;
1781
- let ety = fcx. expr_ty ( e) ;
1782
- fcx. write_ty ( blk. node . id , ety) ;
1783
- }
1784
- }
1785
- if bot {
1786
- fcx. write_bot ( blk. node . id ) ;
1822
+ if bot {
1823
+ fcx. write_bot ( blk. node . id ) ;
1824
+ }
1825
+ bot
1787
1826
}
1788
- vec:: pop ( fcx. blocks ) ;
1789
- ret bot;
1790
1827
}
1791
1828
1792
1829
fn check_const ( ccx : @crate_ctxt , _sp : span , e : @ast:: expr , id : ast:: node_id ) {
1793
1830
let rty = ty:: node_id_to_type ( ccx. tcx , id) ;
1794
- let fcx = blank_fn_ctxt ( ccx, rty) ;
1831
+ let fcx = blank_fn_ctxt ( ccx, rty, e . id ) ;
1795
1832
check_expr ( fcx, e, none) ;
1796
1833
let cty = fcx. expr_ty ( e) ;
1797
1834
let declty = fcx. ccx . tcx . tcache . get ( local_def ( id) ) . ty ;
@@ -1817,13 +1854,13 @@ fn check_enum_variants(ccx: @crate_ctxt,
1817
1854
vs : ~[ ast:: variant ] ,
1818
1855
id : ast:: node_id ) {
1819
1856
let rty = ty:: node_id_to_type ( ccx. tcx , id) ;
1820
- let fcx = blank_fn_ctxt ( ccx, rty) ;
1821
1857
let mut disr_vals: ~[ int ] = ~[ ] ;
1822
1858
let mut disr_val = 0 ;
1823
1859
let mut variants = ~[ ] ;
1824
1860
for vs. each |v| {
1825
1861
alt v. node. disr_expr {
1826
1862
some( e) {
1863
+ let fcx = blank_fn_ctxt( ccx, rty, e. id) ;
1827
1864
check_expr( fcx, e, none) ;
1828
1865
let cty = fcx. expr_ty( e) ;
1829
1866
let declty = ty:: mk_int( ccx. tcx) ;
@@ -2003,7 +2040,7 @@ fn instantiate_path(fcx: @fn_ctxt,
2003
2040
some ( ast_region_to_region ( fcx, fcx, sp, r) )
2004
2041
}
2005
2042
none if tpt. rp => {
2006
- some ( fcx. infcx . next_region_var ( ) )
2043
+ some ( fcx. infcx . next_region_var_nb ( ) )
2007
2044
}
2008
2045
none => {
2009
2046
none
@@ -2037,8 +2074,7 @@ fn instantiate_path(fcx: @fn_ctxt,
2037
2074
// Resolves `typ` by a single level if `typ` is a type variable. If no
2038
2075
// resolution is possible, then an error is reported.
2039
2076
fn structurally_resolved_type ( fcx : @fn_ctxt , sp : span , tp : ty:: t ) -> ty:: t {
2040
- alt infer:: resolve_shallow ( fcx. infcx , tp,
2041
- force_ty_vars_only) {
2077
+ alt infer:: resolve_type ( fcx. infcx , tp, force_tvar) {
2042
2078
result:: ok ( t_s) if !ty:: type_is_var ( t_s) { ret t_s; }
2043
2079
_ {
2044
2080
fcx. ccx . tcx . sess . span_fatal
0 commit comments