regionck: fix bug where autoref regions are not inferred to be large enough
This commit is contained in:
parent
6332c2d728
commit
39d33a653f
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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],
|
||||
|
Loading…
x
Reference in New Issue
Block a user