Skip to content

Commit bd159d3

Browse files
committed
auto merge of #15955 : nikomatsakis/rust/issue-5527-new-inference-scheme, r=pcwalton
The inference scheme proposed in <http://smallcultfollowing.com/babysteps/blog/2014/07/09/an-experimental-new-type-inference-scheme-for-rust/>. This is theoretically a [breaking-change]. It is possible that you may encounter type checking errors, particularly related to closures or functions with higher-ranked lifetimes or object types. Adding more explicit type annotations should help the problem. However, I have not been able to make an example that *actually* successfully compiles with the older scheme and fails with the newer scheme. f? @pcwalton, @pnkfelix
2 parents 51d0d06 + 6e27c2f commit bd159d3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1535
-1054
lines changed

src/librustc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ pub mod util {
136136
pub mod common;
137137
pub mod ppaux;
138138
pub mod nodemap;
139+
pub mod snapshot_vec;
139140
}
140141

141142
pub mod lib {

src/librustc/middle/ty.rs

-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ use middle::subst::{Subst, Substs, VecPerParamSpace};
3030
use middle::subst;
3131
use middle::ty;
3232
use middle::typeck;
33-
use middle::typeck::MethodCall;
3433
use middle::ty_fold;
3534
use middle::ty_fold::{TypeFoldable,TypeFolder};
3635
use middle;

src/librustc/middle/typeck/check/regionck.rs

+190-84
Original file line numberDiff line numberDiff line change
@@ -1381,8 +1381,8 @@ fn link_by_ref(rcx: &Rcx,
13811381
expr.repr(tcx), callee_scope);
13821382
let mc = mc::MemCategorizationContext::new(rcx);
13831383
let expr_cmt = ignore_err!(mc.cat_expr(expr));
1384-
let region_min = ty::ReScope(callee_scope);
1385-
link_region(rcx, expr.span, region_min, ty::ImmBorrow, expr_cmt);
1384+
let borrow_region = ty::ReScope(callee_scope);
1385+
link_region(rcx, expr.span, borrow_region, ty::ImmBorrow, expr_cmt);
13861386
}
13871387

13881388
fn link_region_from_node_type(rcx: &Rcx,
@@ -1408,102 +1408,54 @@ fn link_region_from_node_type(rcx: &Rcx,
14081408

14091409
fn link_region(rcx: &Rcx,
14101410
span: Span,
1411-
region_min: ty::Region,
1412-
kind: ty::BorrowKind,
1413-
cmt_borrowed: mc::cmt) {
1411+
borrow_region: ty::Region,
1412+
borrow_kind: ty::BorrowKind,
1413+
borrow_cmt: mc::cmt) {
14141414
/*!
1415-
* Informs the inference engine that a borrow of `cmt`
1416-
* must have the borrow kind `kind` and lifetime `region_min`.
1417-
* If `cmt` is a deref of a region pointer with
1418-
* lifetime `r_borrowed`, this will add the constraint that
1419-
* `region_min <= r_borrowed`.
1415+
* Informs the inference engine that `borrow_cmt` is being
1416+
* borrowed with kind `borrow_kind` and lifetime `borrow_region`.
1417+
* In order to ensure borrowck is satisfied, this may create
1418+
* constraints between regions, as explained in
1419+
* `link_reborrowed_region()`.
14201420
*/
14211421

1422-
// Iterate through all the things that must be live at least
1423-
// for the lifetime `region_min` for the borrow to be valid:
1424-
let mut cmt_borrowed = cmt_borrowed;
1422+
let mut borrow_cmt = borrow_cmt;
1423+
let mut borrow_kind = borrow_kind;
1424+
14251425
loop {
1426-
debug!("link_region(region_min={}, kind={}, cmt_borrowed={})",
1427-
region_min.repr(rcx.tcx()),
1428-
kind.repr(rcx.tcx()),
1429-
cmt_borrowed.repr(rcx.tcx()));
1430-
match cmt_borrowed.cat.clone() {
1431-
mc::cat_deref(base, _, mc::BorrowedPtr(_, r_borrowed)) |
1432-
mc::cat_deref(base, _, mc::Implicit(_, r_borrowed)) => {
1433-
// References to an upvar `x` are translated to
1434-
// `*x`, since that is what happens in the
1435-
// underlying machine. We detect such references
1436-
// and treat them slightly differently, both to
1437-
// offer better error messages and because we need
1438-
// to infer the kind of borrow (mut, const, etc)
1439-
// to use for each upvar.
1440-
let cause = match base.cat {
1441-
mc::cat_upvar(ref upvar_id, _) => {
1442-
match rcx.fcx.inh.upvar_borrow_map.borrow_mut()
1443-
.find_mut(upvar_id) {
1444-
Some(upvar_borrow) => {
1445-
debug!("link_region: {} <= {}",
1446-
region_min.repr(rcx.tcx()),
1447-
upvar_borrow.region.repr(rcx.tcx()));
1448-
adjust_upvar_borrow_kind_for_loan(
1449-
*upvar_id,
1450-
upvar_borrow,
1451-
kind);
1452-
infer::ReborrowUpvar(span, *upvar_id)
1453-
}
1454-
None => {
1455-
rcx.tcx().sess.span_bug(
1456-
span,
1457-
format!("Illegal upvar id: {}",
1458-
upvar_id.repr(
1459-
rcx.tcx())).as_slice());
1460-
}
1461-
}
1426+
debug!("link_region(borrow_region={}, borrow_kind={}, borrow_cmt={})",
1427+
borrow_region.repr(rcx.tcx()),
1428+
borrow_kind.repr(rcx.tcx()),
1429+
borrow_cmt.repr(rcx.tcx()));
1430+
match borrow_cmt.cat.clone() {
1431+
mc::cat_deref(ref_cmt, _,
1432+
mc::Implicit(ref_kind, ref_region)) |
1433+
mc::cat_deref(ref_cmt, _,
1434+
mc::BorrowedPtr(ref_kind, ref_region)) => {
1435+
match link_reborrowed_region(rcx, span,
1436+
borrow_region, borrow_kind,
1437+
ref_cmt, ref_region, ref_kind) {
1438+
Some((c, k)) => {
1439+
borrow_cmt = c;
1440+
borrow_kind = k;
14621441
}
1463-
1464-
_ => {
1465-
infer::Reborrow(span)
1442+
None => {
1443+
return;
14661444
}
1467-
};
1468-
1469-
debug!("link_region: {} <= {}",
1470-
region_min.repr(rcx.tcx()),
1471-
r_borrowed.repr(rcx.tcx()));
1472-
rcx.fcx.mk_subr(cause, region_min, r_borrowed);
1473-
1474-
if kind != ty::ImmBorrow {
1475-
// If this is a mutable borrow, then the thing
1476-
// being borrowed will have to be unique.
1477-
// In user code, this means it must be an `&mut`
1478-
// borrow, but for an upvar, we might opt
1479-
// for an immutable-unique borrow.
1480-
adjust_upvar_borrow_kind_for_unique(rcx, base);
14811445
}
1482-
1483-
// Borrowing an `&mut` pointee for `region_min` is
1484-
// only valid if the pointer resides in a unique
1485-
// location which is itself valid for
1486-
// `region_min`. We don't care about the unique
1487-
// part, but we may need to influence the
1488-
// inference to ensure that the location remains
1489-
// valid.
1490-
//
1491-
// FIXME(#8624) fixing borrowck will require this
1492-
// if m == ast::m_mutbl {
1493-
// cmt_borrowed = cmt_base;
1494-
// } else {
1495-
// return;
1496-
// }
1497-
return;
14981446
}
1447+
14991448
mc::cat_discr(cmt_base, _) |
15001449
mc::cat_downcast(cmt_base) |
15011450
mc::cat_deref(cmt_base, _, mc::GcPtr(..)) |
15021451
mc::cat_deref(cmt_base, _, mc::OwnedPtr) |
15031452
mc::cat_interior(cmt_base, _) => {
1504-
// Interior or owned data requires its base to be valid
1505-
cmt_borrowed = cmt_base;
1453+
// Borrowing interior or owned data requires the base
1454+
// to be valid and borrowable in the same fashion.
1455+
borrow_cmt = cmt_base;
1456+
borrow_kind = borrow_kind;
15061457
}
1458+
15071459
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
15081460
mc::cat_static_item |
15091461
mc::cat_copied_upvar(..) |
@@ -1519,6 +1471,154 @@ fn link_region(rcx: &Rcx,
15191471
}
15201472
}
15211473

1474+
fn link_reborrowed_region(rcx: &Rcx,
1475+
span: Span,
1476+
borrow_region: ty::Region,
1477+
borrow_kind: ty::BorrowKind,
1478+
ref_cmt: mc::cmt,
1479+
ref_region: ty::Region,
1480+
ref_kind: ty::BorrowKind)
1481+
-> Option<(mc::cmt, ty::BorrowKind)>
1482+
{
1483+
/*!
1484+
* This is the most complicated case: the path being borrowed is
1485+
* itself the referent of a borrowed pointer. Let me give an
1486+
* example fragment of code to make clear(er) the situation:
1487+
*
1488+
* let r: &'a mut T = ...; // the original reference "r" has lifetime 'a
1489+
* ...
1490+
* &'z *r // the reborrow has lifetime 'z
1491+
*
1492+
* Now, in this case, our primary job is to add the inference
1493+
* constraint that `'z <= 'a`. Given this setup, let's clarify the
1494+
* parameters in (roughly) terms of the example:
1495+
*
1496+
* A borrow of: `& 'z bk * r` where `r` has type `& 'a bk T`
1497+
* borrow_region ^~ ref_region ^~
1498+
* borrow_kind ^~ ref_kind ^~
1499+
* ref_cmt ^
1500+
*
1501+
* Here `bk` stands for some borrow-kind (e.g., `mut`, `uniq`, etc).
1502+
*
1503+
* Unfortunately, there are some complications beyond the simple
1504+
* scenario I just painted:
1505+
*
1506+
* 1. The reference `r` might in fact be a "by-ref" upvar. In that
1507+
* case, we have two jobs. First, we are inferring whether this reference
1508+
* should be an `&T`, `&mut T`, or `&uniq T` reference, and we must
1509+
* adjust that based on this borrow (e.g., if this is an `&mut` borrow,
1510+
* then `r` must be an `&mut` reference). Second, whenever we link
1511+
* two regions (here, `'z <= 'a`), we supply a *cause*, and in this
1512+
* case we adjust the cause to indicate that the reference being
1513+
* "reborrowed" is itself an upvar. This provides a nicer error message
1514+
* should something go wrong.
1515+
*
1516+
* 2. There may in fact be more levels of reborrowing. In the
1517+
* example, I said the borrow was like `&'z *r`, but it might
1518+
* in fact be a borrow like `&'z **q` where `q` has type `&'a
1519+
* &'b mut T`. In that case, we want to ensure that `'z <= 'a`
1520+
* and `'z <= 'b`. This is explained more below.
1521+
*
1522+
* The return value of this function indicates whether we need to
1523+
* recurse and process `ref_cmt` (see case 2 above).
1524+
*/
1525+
1526+
// Detect references to an upvar `x`:
1527+
let cause = match ref_cmt.cat {
1528+
mc::cat_upvar(ref upvar_id, _) => {
1529+
let mut upvar_borrow_map =
1530+
rcx.fcx.inh.upvar_borrow_map.borrow_mut();
1531+
match upvar_borrow_map.find_mut(upvar_id) {
1532+
Some(upvar_borrow) => {
1533+
// Adjust mutability that we infer for the upvar
1534+
// so it can accommodate being borrowed with
1535+
// mutability `kind`:
1536+
adjust_upvar_borrow_kind_for_loan(*upvar_id,
1537+
upvar_borrow,
1538+
borrow_kind);
1539+
1540+
infer::ReborrowUpvar(span, *upvar_id)
1541+
}
1542+
None => {
1543+
rcx.tcx().sess.span_bug(
1544+
span,
1545+
format!("Illegal upvar id: {}",
1546+
upvar_id.repr(
1547+
rcx.tcx())).as_slice());
1548+
}
1549+
}
1550+
}
1551+
1552+
_ => {
1553+
infer::Reborrow(span)
1554+
}
1555+
};
1556+
1557+
debug!("link_reborrowed_region: {} <= {}",
1558+
borrow_region.repr(rcx.tcx()),
1559+
ref_region.repr(rcx.tcx()));
1560+
rcx.fcx.mk_subr(cause, borrow_region, ref_region);
1561+
1562+
// Decide whether we need to recurse and link any regions within
1563+
// the `ref_cmt`. This is concerned for the case where the value
1564+
// being reborrowed is in fact a borrowed pointer found within
1565+
// another borrowed pointer. For example:
1566+
//
1567+
// let p: &'b &'a mut T = ...;
1568+
// ...
1569+
// &'z **p
1570+
//
1571+
// What makes this case particularly tricky is that, if the data
1572+
// being borrowed is a `&mut` or `&uniq` borrow, borrowck requires
1573+
// not only that `'z <= 'a`, (as before) but also `'z <= 'b`
1574+
// (otherwise the user might mutate through the `&mut T` reference
1575+
// after `'b` expires and invalidate the borrow we are looking at
1576+
// now).
1577+
//
1578+
// So let's re-examine our parameters in light of this more
1579+
// complicated (possible) scenario:
1580+
//
1581+
// A borrow of: `& 'z bk * * p` where `p` has type `&'b bk & 'a bk T`
1582+
// borrow_region ^~ ref_region ^~
1583+
// borrow_kind ^~ ref_kind ^~
1584+
// ref_cmt ^~~
1585+
//
1586+
// (Note that since we have not examined `ref_cmt.cat`, we don't
1587+
// know whether this scenario has occurred; but I wanted to show
1588+
// how all the types get adjusted.)
1589+
match ref_kind {
1590+
ty::ImmBorrow => {
1591+
// The reference being reborrowed is a sharable ref of
1592+
// type `&'a T`. In this case, it doesn't matter where we
1593+
// *found* the `&T` pointer, the memory it references will
1594+
// be valid and immutable for `'a`. So we can stop here.
1595+
//
1596+
// (Note that the `borrow_kind` must also be ImmBorrow or
1597+
// else the user is borrowed imm memory as mut memory,
1598+
// which means they'll get an error downstream in borrowck
1599+
// anyhow.)
1600+
return None;
1601+
}
1602+
1603+
ty::MutBorrow | ty::UniqueImmBorrow => {
1604+
// The reference being reborrowed is either an `&mut T` or
1605+
// `&uniq T`. This is the case where recursion is needed.
1606+
//
1607+
// One interesting twist is that we can weaken the borrow
1608+
// kind when we recurse: to reborrow an `&mut` referent as
1609+
// mutable, borrowck requires a unique path to the `&mut`
1610+
// reference but not necessarily a *mutable* path.
1611+
let new_borrow_kind = match borrow_kind {
1612+
ty::ImmBorrow =>
1613+
ty::ImmBorrow,
1614+
ty::MutBorrow | ty::UniqueImmBorrow =>
1615+
ty::UniqueImmBorrow
1616+
};
1617+
return Some((ref_cmt, new_borrow_kind));
1618+
}
1619+
}
1620+
}
1621+
15221622
fn adjust_borrow_kind_for_assignment_lhs(rcx: &Rcx,
15231623
lhs: &ast::Expr) {
15241624
/*!
@@ -1534,6 +1634,12 @@ fn adjust_borrow_kind_for_assignment_lhs(rcx: &Rcx,
15341634

15351635
fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx,
15361636
cmt: mc::cmt) {
1637+
/*!
1638+
* Indicates that `cmt` is being directly mutated (e.g., assigned
1639+
* to). If cmt contains any by-ref upvars, this implies that
1640+
* those upvars must be borrowed using an `&mut` borow.
1641+
*/
1642+
15371643
let mut cmt = cmt;
15381644
loop {
15391645
debug!("adjust_upvar_borrow_kind_for_mut(cmt={})",

src/librustc/middle/typeck/infer/coercion.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ impl<'f> Coerce<'f> {
247247
let a_borrowed = ty::mk_rptr(self.get_ref().infcx.tcx,
248248
r_borrow,
249249
mt {ty: inner_ty, mutbl: mutbl_b});
250-
if_ok!(sub.tys(a_borrowed, b));
250+
try!(sub.tys(a_borrowed, b));
251251

252252
Ok(Some(AutoDerefRef(AutoDerefRef {
253253
autoderefs: 1,
@@ -273,7 +273,7 @@ impl<'f> Coerce<'f> {
273273
let r_borrow = self.get_ref().infcx.next_region_var(coercion);
274274
let unsized_ty = ty::mk_slice(self.get_ref().infcx.tcx, r_borrow,
275275
mt {ty: t_a, mutbl: mutbl_b});
276-
if_ok!(self.get_ref().infcx.try(|| sub.tys(unsized_ty, b)));
276+
try!(self.get_ref().infcx.try(|| sub.tys(unsized_ty, b)));
277277
Ok(Some(AutoDerefRef(AutoDerefRef {
278278
autoderefs: 0,
279279
autoref: Some(ty::AutoPtr(r_borrow,
@@ -316,7 +316,7 @@ impl<'f> Coerce<'f> {
316316
let ty = ty::mk_rptr(self.get_ref().infcx.tcx,
317317
r_borrow,
318318
ty::mt{ty: ty, mutbl: mt_b.mutbl});
319-
if_ok!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
319+
try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
320320
debug!("Success, coerced with AutoDerefRef(1, \
321321
AutoPtr(AutoUnsize({:?})))", kind);
322322
Ok(Some(AutoDerefRef(AutoDerefRef {
@@ -334,7 +334,7 @@ impl<'f> Coerce<'f> {
334334
match self.unsize_ty(sty_a, t_b) {
335335
Some((ty, kind)) => {
336336
let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty);
337-
if_ok!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
337+
try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
338338
debug!("Success, coerced with AutoDerefRef(1, \
339339
AutoUnsizeUniq({:?}))", kind);
340340
Ok(Some(AutoDerefRef(AutoDerefRef {
@@ -458,7 +458,7 @@ impl<'f> Coerce<'f> {
458458
}
459459
};
460460

461-
if_ok!(self.subtype(a_borrowed, b));
461+
try!(self.subtype(a_borrowed, b));
462462
Ok(Some(AutoDerefRef(AutoDerefRef {
463463
autoderefs: 1,
464464
autoref: Some(AutoPtr(r_a, b_mutbl, None))
@@ -512,7 +512,7 @@ impl<'f> Coerce<'f> {
512512
sig: fn_ty_a.sig.clone(),
513513
.. *fn_ty_b
514514
});
515-
if_ok!(self.subtype(a_closure, b));
515+
try!(self.subtype(a_closure, b));
516516
Ok(Some(adj))
517517
})
518518
}
@@ -536,7 +536,7 @@ impl<'f> Coerce<'f> {
536536

537537
// check that the types which they point at are compatible
538538
let a_unsafe = ty::mk_ptr(self.get_ref().infcx.tcx, mt_a);
539-
if_ok!(self.subtype(a_unsafe, b));
539+
try!(self.subtype(a_unsafe, b));
540540

541541
// although references and unsafe ptrs have the same
542542
// representation, we still register an AutoDerefRef so that

0 commit comments

Comments
 (0)