From a334deb5d58c455e20fececea649c4997c6867ca Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 31 Jul 2012 21:08:24 -0700 Subject: [PATCH] change how we print and explain region types --- src/rustc/middle/ty.rs | 10 ++- src/rustc/util/ppaux.rs | 70 ++++++++++++++++++++- src/test/compile-fail/regions-nested-fns.rs | 6 +- src/test/compile-fail/regions-scoping.rs | 2 +- 4 files changed, 75 insertions(+), 13 deletions(-) diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 71e0fedef61..aba8d250b20 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -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", diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs index bf97df5fd5f..f6f0cf8b363 100644 --- a/src/rustc/util/ppaux.rs +++ b/src/rustc/util/ppaux.rs @@ -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: diff --git a/src/test/compile-fail/regions-nested-fns.rs b/src/test/compile-fail/regions-nested-fns.rs index ae3102b8ec2..bd6e3644556 100644 --- a/src/test/compile-fail/regions-nested-fns.rs +++ b/src/test/compile-fail/regions-nested-fns.rs @@ -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; }); } diff --git a/src/test/compile-fail/regions-scoping.rs b/src/test/compile-fail/regions-scoping.rs index 8526c6722f4..c17319ca7bb 100644 --- a/src/test/compile-fail/regions-scoping.rs +++ b/src/test/compile-fail/regions-scoping.rs @@ -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 `&