regionck: fix bug where autoref regions are not inferred to be large enough

This commit is contained in:
Niko Matsakis 2012-09-14 21:58:04 -07:00
parent 6332c2d728
commit 39d33a653f
4 changed files with 102 additions and 45 deletions

View file

@ -338,39 +338,49 @@ impl gather_loan_ctxt {
};
match result {
Ok(pc_ok) => {
// we were able guarantee the validity of the ptr,
// perhaps by rooting or because it is immutably
// rooted. good.
self.bccx.stable_paths += 1;
}
Ok(pc_if_pure(e)) => {
// we are only able to guarantee the validity if
// the scope is pure
match scope_r {
ty::re_scope(pure_id) => {
// if the scope is some block/expr in the fn,
// then just require that this scope be pure
self.req_maps.pure_map.insert(pure_id, e);
self.bccx.req_pure_paths += 1;
Ok(pc_ok) => {
debug!("result of preserve: pc_ok");
if self.tcx().sess.borrowck_note_pure() {
self.bccx.span_note(
cmt.span,
fmt!("purity required"));
}
}
_ => {
// otherwise, we can't enforce purity for that
// scope, so give up and report an error
self.bccx.report(e);
}
// we were able guarantee the validity of the ptr,
// perhaps by rooting or because it is immutably
// rooted. good.
self.bccx.stable_paths += 1;
}
Ok(pc_if_pure(e)) => {
debug!("result of preserve: %?", pc_if_pure(e));
// we are only able to guarantee the validity if
// the scope is pure
match scope_r {
ty::re_scope(pure_id) => {
// if the scope is some block/expr in the
// fn, then just require that this scope
// be pure
self.req_maps.pure_map.insert(pure_id, e);
self.bccx.req_pure_paths += 1;
debug!("requiring purity for scope %?",
scope_r);
if self.tcx().sess.borrowck_note_pure() {
self.bccx.span_note(
cmt.span,
fmt!("purity required"));
}
}
_ => {
// otherwise, we can't enforce purity for
// that scope, so give up and report an
// error
self.bccx.report(e);
}
}
}
Err(e) => {
// we cannot guarantee the validity of this pointer
debug!("result of preserve: error");
self.bccx.report(e);
}
}
Err(e) => {
// we cannot guarantee the validity of this pointer
self.bccx.report(e);
}
}
}
}
@ -386,13 +396,19 @@ impl gather_loan_ctxt {
// mutable memory.
fn check_mutbl(req_mutbl: ast::mutability,
cmt: cmt) -> bckres<preserve_condition> {
debug!("check_mutbl(req_mutbl=%?, cmt.mutbl=%?)",
req_mutbl, cmt.mutbl);
if req_mutbl == m_const || req_mutbl == cmt.mutbl {
debug!("required is const or they are the same");
Ok(pc_ok)
} else {
let e = {cmt: cmt,
code: err_mutbl(req_mutbl)};
if req_mutbl == m_imm {
// you can treat mutable things as imm if you are pure
debug!("imm required, must be pure");
Ok(pc_if_pure(e))
} else {
Err(e)

View file

@ -758,6 +758,9 @@ impl LookupContext {
}
fn is_relevant(&self, self_ty: ty::t, candidate: &Candidate) -> bool {
debug!("is_relevant(self_ty=%s, candidate=%s)",
self.ty_to_str(self_ty), self.cand_to_str(candidate));
self.fcx.can_mk_subty(self_ty, candidate.rcvr_ty).is_ok()
}
@ -782,7 +785,7 @@ impl LookupContext {
}
}
fn report_candidate(idx: uint, origin: &method_origin) {
fn report_candidate(&self, idx: uint, origin: &method_origin) {
match *origin {
method_static(impl_did) => {
self.report_static_candidate(idx, impl_did)
@ -796,7 +799,7 @@ impl LookupContext {
}
}
fn report_static_candidate(idx: uint, did: def_id) {
fn report_static_candidate(&self, idx: uint, did: def_id) {
let span = if did.crate == ast::local_crate {
match self.tcx().items.get(did.node) {
ast_map::node_method(m, _, _) => m.span,
@ -812,7 +815,7 @@ impl LookupContext {
ty::item_path_str(self.tcx(), did)));
}
fn report_param_candidate(idx: uint, did: def_id) {
fn report_param_candidate(&self, idx: uint, did: def_id) {
self.tcx().sess.span_note(
self.expr.span,
fmt!("candidate #%u derives from the bound `%s`",
@ -820,7 +823,7 @@ impl LookupContext {
ty::item_path_str(self.tcx(), did)));
}
fn report_trait_candidate(idx: uint, did: def_id) {
fn report_trait_candidate(&self, idx: uint, did: def_id) {
self.tcx().sess.span_note(
self.expr.span,
fmt!("candidate #%u derives from the type of the receiver, \
@ -829,23 +832,31 @@ impl LookupContext {
ty::item_path_str(self.tcx(), did)));
}
fn infcx() -> infer::infer_ctxt {
fn infcx(&self) -> infer::infer_ctxt {
self.fcx.inh.infcx
}
fn tcx() -> ty::ctxt {
fn tcx(&self) -> ty::ctxt {
self.fcx.tcx()
}
fn ty_to_str(t: ty::t) -> ~str {
fn ty_to_str(&self, t: ty::t) -> ~str {
self.fcx.infcx().ty_to_str(t)
}
fn did_to_str(did: def_id) -> ~str {
fn cand_to_str(&self, cand: &Candidate) -> ~str {
fmt!("Candidate(rcvr_ty=%s, rcvr_substs=%s, self_mode=%?, origin=%?)",
self.ty_to_str(cand.rcvr_ty),
ty::substs_to_str(self.tcx(), &cand.rcvr_substs),
cand.self_mode,
cand.origin)
}
fn did_to_str(&self, did: def_id) -> ~str {
ty::item_path_str(self.tcx(), did)
}
fn bug(s: ~str) -> ! {
fn bug(&self, s: ~str) -> ! {
self.tcx().sess.bug(s)
}
}

View file

@ -159,8 +159,6 @@ fn visit_expr(expr: @ast::expr, &&rcx: @rcx, v: rvt) {
debug!("visit_expr(e=%s)",
pprust::expr_to_str(expr, rcx.fcx.tcx().sess.intr()));
// constrain_auto_ref(rcx, expr);
match expr.node {
ast::expr_path(*) => {
// Avoid checking the use of local variables, as we
@ -176,6 +174,36 @@ fn visit_expr(expr: @ast::expr, &&rcx: @rcx, v: rvt) {
}
}
ast::expr_call(callee, args, _) => {
// Check for a.b() where b is a method. Ensure that
// any types in the callee are valid for the entire
// method call.
// FIXME(#3387)--we should really invoke
// `constrain_auto_ref()` on all exprs. But that causes a
// lot of spurious errors because of how the region
// hierarchy is setup.
let tcx = rcx.fcx.tcx();
if rcx.fcx.ccx.method_map.contains_key(callee.id) {
match callee.node {
ast::expr_field(base, _, _) => {
constrain_auto_ref(rcx, base);
}
_ => {
tcx.sess.span_bug(
callee.span,
~"call of method that is not a field");
}
}
} else {
constrain_auto_ref(rcx, callee);
}
for args.each |arg| {
constrain_auto_ref(rcx, arg);
}
}
ast::expr_cast(source, _) => {
// Determine if we are casting `source` to an trait
// instance. If so, we have to be sure that the type of
@ -275,6 +303,8 @@ fn constrain_auto_ref(
* function ensures that the lifetime of the resulting borrowed
* ptr includes at least the expression `expr`. */
debug!("constrain_auto_ref(expr=%s)", rcx.fcx.expr_to_str(expr));
let adjustment = rcx.fcx.inh.adjustments.find(expr.id);
let region = match adjustment {
Some(@{autoref: Some(ref auto_ref), _}) => auto_ref.region,
@ -282,8 +312,8 @@ fn constrain_auto_ref(
};
let tcx = rcx.fcx.tcx();
let expr_region = ty::re_scope(expr.id);
match rcx.fcx.mk_subr(true, expr.span, expr_region, region) {
let encl_region = ty::encl_region(tcx, expr.id);
match rcx.fcx.mk_subr(true, expr.span, encl_region, region) {
result::Ok(()) => {}
result::Err(_) => {
// In practice, this cannot happen: `region` is always a

View file

@ -583,7 +583,7 @@ impl RegionVarBindings {
}
fn resolve_var(rid: RegionVid) -> ty::region {
debug!("RegionVarBindings: resolve_var(%?)", rid);
debug!("RegionVarBindings: resolve_var(%?=%u)", rid, *rid);
if self.values.is_empty() {
self.tcx.sess.span_bug(
self.var_spans[*rid],