change how we print and explain region types

This commit is contained in:
Niko Matsakis 2012-07-31 21:08:24 -07:00
parent c5437c0bbf
commit a334deb5d5
4 changed files with 75 additions and 13 deletions
src

@ -9,8 +9,7 @@ import syntax::ast_util::{is_local, local_def, split_class_items,
new_def_hash};
import syntax::codemap::span;
import metadata::csearch;
import util::ppaux::region_to_str;
import util::ppaux::vstore_to_str;
import util::ppaux::{region_to_str, explain_region, vstore_to_str};
import middle::lint;
import middle::lint::{get_lint_level, allow};
import syntax::ast::*;
@ -2590,10 +2589,9 @@ fn type_err_to_str(cx: ctxt, err: type_err) -> ~str {
~" but found " + mode_to_str(a_mode);
}
terr_regions_differ(subregion, superregion) {
ret fmt!{"references with lifetime %s do not necessarily \
outlive references with lifetime %s",
region_to_str(cx, subregion),
region_to_str(cx, superregion)};
ret fmt!{"%s does not necessarily outlive %s",
explain_region(cx, subregion),
explain_region(cx, superregion)};
}
terr_vstores_differ(k, e_vs, a_vs) {
ret fmt!{"%s storage differs: expected %s but found %s",

@ -3,7 +3,8 @@ import middle::ty;
import middle::ty::{arg, canon_mode};
import middle::ty::{bound_region, br_anon, br_named, br_self, br_cap_avoid};
import middle::ty::{ck_block, ck_box, ck_uniq, ctxt, field, method};
import middle::ty::{mt, re_bound, re_free, re_scope, re_var, region, t};
import middle::ty::{mt, t};
import middle::ty::{re_bound, re_free, re_scope, re_var, re_static, region};
import middle::ty::{ty_bool, ty_bot, ty_box, ty_class, ty_enum};
import middle::ty::{ty_estr, ty_evec, ty_float, ty_fn, ty_trait, ty_int};
import middle::ty::{ty_nil, ty_opaque_box, ty_opaque_closure_ptr, ty_param};
@ -12,6 +13,7 @@ import middle::ty::{ty_type, ty_uniq, ty_uint, ty_var, ty_var_integral};
import middle::ty::{ty_unboxed_vec, vid};
import metadata::encoder;
import syntax::codemap;
import syntax::codemap::span;
import syntax::print::pprust;
import syntax::print::pprust::{path_to_str, proto_to_str,
mode_to_str, purity_to_str};
@ -19,6 +21,60 @@ import syntax::{ast, ast_util};
import syntax::ast_map;
import driver::session::session;
/// Returns a string like "reference valid for the block at 27:31 in foo.rs"
/// that attempts to explain a lifetime in a way it might plausibly be
/// understood.
fn explain_region(cx: ctxt, region: ty::region) -> ~str {
ret alt region {
re_scope(node_id) => {
let scope_str = alt cx.items.find(node_id) {
some(ast_map::node_block(blk)) => {
explain_span(cx, ~"block", blk.span)
}
some(ast_map::node_expr(expr)) => {
alt expr.node {
ast::expr_call(*) => { explain_span(cx, ~"call", expr.span) }
ast::expr_alt(*) => { explain_span(cx, ~"alt", expr.span) }
_ => { explain_span(cx, ~"expression", expr.span) }
}
}
some(_) | none => {
// this really should not happen
fmt!{"unknown scope: %d. Please report a bug.", node_id}
}
};
fmt!{"reference valid for the %s", scope_str}
}
re_free(id, br) => {
alt cx.items.find(id) {
some(ast_map::node_block(blk)) => {
fmt!{"reference with lifetime %s as defined on %s",
bound_region_to_str(cx, br),
explain_span(cx, ~"the block", blk.span)}
}
some(_) | none => {
// this really should not happen
fmt!{"reference with lifetime %s as defined on node %d",
bound_region_to_str(cx, br), id}
}
}
}
re_static => { ~"reference to static data" }
// I believe these cases should not occur.
re_var(_) | re_bound(_) => {
fmt!{"reference with lifetime %?", region}
}
};
fn explain_span(cx: ctxt, heading: ~str, span: span) -> ~str {
let lo = codemap::lookup_char_pos_adj(cx.sess.codemap, span.lo);
fmt!{"%s at %u:%u", heading, lo.line, lo.col}
}
}
fn bound_region_to_str(cx: ctxt, br: bound_region) -> ~str {
alt br {
br_anon => { ~"&" }
@ -79,8 +135,16 @@ fn re_scope_id_to_str(cx: ctxt, node_id: ast::node_id) -> ~str {
fn region_to_str(cx: ctxt, region: region) -> ~str {
alt region {
re_scope(node_id) { fmt!{"&%s", re_scope_id_to_str(cx, node_id)} }
re_bound(br) { bound_region_to_str(cx, br) }
re_scope(node_id) {
if cx.sess.ppregions() {
fmt!{"&%s", re_scope_id_to_str(cx, node_id)}
} else {
~"&"
}
}
re_bound(br) {
bound_region_to_str(cx, br)
}
re_free(id, br) {
if cx.sess.ppregions() {
// For debugging, this version is sometimes helpful:

@ -7,12 +7,12 @@ fn nested(x: &x/int) {
ignore(fn&(z: &z/int) {
ay = x;
ay = &y;
ay = z; //~ ERROR references with lifetime
ay = z; //~ ERROR mismatched types
});
ignore(fn&(z: &z/int) -> &z/int {
if false { ret x; } //~ ERROR references with lifetime
if false { ret ay; } //~ ERROR references with lifetime
if false { ret x; } //~ ERROR mismatched types
if false { ret ay; } //~ ERROR mismatched types
ret z;
});
}

@ -41,7 +41,7 @@ fn nested(x: &x/int) { // (1)
// let f: &x/int = foo(&z, &z, |_x, _y, z| z ); // ERROR mismatched types: expected `&x/int` but found
foo(x, &z, |x, _y, _z| x ); //~ ERROR mismatched types: expected `&z/int` but found `&x/int`
foo(x, &z, |_x, y, _z| y ); //~ ERROR mismatched types: expected `&z/int` but found `&<expression at
foo(x, &z, |_x, y, _z| y ); //~ ERROR mismatched types: expected `&z/int` but found `&
}
}