提交 3280e5a3 编写于 作者: N Niko Matsakis

Improve error messages when illegal lifetimes are used

上级 d26f6edd
......@@ -58,14 +58,14 @@
use middle::ty::{ty_param_substs_and_ty};
use middle::ty;
use middle::typeck::rscope::{in_binding_rscope};
use middle::typeck::rscope::{region_scope, type_rscope};
use middle::typeck::rscope::{region_scope, type_rscope, RegionError};
use middle::typeck::{CrateCtxt, write_substs_to_tcx, write_ty_to_tcx};
use core::result;
use core::vec;
use syntax::ast;
use syntax::codemap::span;
use syntax::print::pprust::path_to_str;
use syntax::print::pprust::{region_to_str, path_to_str};
use util::common::indenter;
pub trait AstConv {
......@@ -76,17 +76,31 @@ pub trait AstConv {
fn ty_infer(&self, span: span) -> ty::t;
}
pub fn get_region_reporting_err(tcx: ty::ctxt,
span: span,
res: Result<ty::Region, ~str>)
-> ty::Region {
pub fn get_region_reporting_err(
tcx: ty::ctxt,
span: span,
a_r: Option<@ast::region>,
res: Result<ty::Region, RegionError>) -> ty::Region
{
match res {
result::Ok(r) => r,
result::Err(ref e) => {
tcx.sess.span_err(span, (/*bad*/copy *e));
ty::re_static
}
result::Ok(r) => r,
result::Err(ref e) => {
let descr = match a_r {
None => ~"anonymous lifetime",
Some(a) if a.node == ast::re_anon => {
~"anonymous lifetime"
}
Some(a) => {
fmt!("lifetime %s",
region_to_str(a, tcx.sess.intr()))
}
};
tcx.sess.span_err(
span,
fmt!("Illegal %s: %s",
descr, e.msg));
e.replacement
}
}
}
......@@ -103,7 +117,7 @@ pub fn ast_region_to_region<AC:AstConv,RS:region_scope + Copy + Durable>(
ast::re_named(id) => rscope.named_region(span, id)
};
get_region_reporting_err(self.tcx(), span, res)
get_region_reporting_err(self.tcx(), span, Some(a_r), res)
}
pub fn ast_path_to_substs_and_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
......@@ -139,7 +153,7 @@ pub fn ast_path_to_substs_and_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
}
(Some(_), None) => {
let res = rscope.anon_region(path.span);
let r = get_region_reporting_err(self.tcx(), path.span, res);
let r = get_region_reporting_err(self.tcx(), path.span, None, res);
Some(r)
}
(Some(_), Some(r)) => {
......@@ -521,7 +535,7 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + Durable>(
ast::BorrowedSigil => {
// &fn() defaults to an anonymous region:
let r_result = rscope.anon_region(span);
get_region_reporting_err(self.tcx(), span, r_result)
get_region_reporting_err(self.tcx(), span, None, r_result)
}
}
}
......
n// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
......@@ -96,6 +96,7 @@
use middle::typeck::infer::{resolve_type, force_tvar};
use middle::typeck::infer;
use middle::typeck::rscope::{binding_rscope, bound_self_region};
use middle::typeck::rscope::{RegionError};
use middle::typeck::rscope::{in_binding_rscope, region_scope, type_rscope};
use middle::typeck::rscope;
use middle::typeck::{isr_alist, lookup_def_ccx, method_map_entry};
......@@ -651,7 +652,8 @@ pub impl FnCtxt {
fn infcx(&self) -> @mut infer::InferCtxt { self.inh.infcx }
fn search_in_scope_regions(
&self,
br: ty::bound_region) -> Result<ty::Region, ~str>
span: span,
br: ty::bound_region) -> Result<ty::Region, RegionError>
{
let in_scope_regions = self.in_scope_regions;
match in_scope_regions.find(br) {
......@@ -661,8 +663,11 @@ fn search_in_scope_regions(
if br == blk_br {
result::Ok(self.block_region())
} else {
result::Err(fmt!("named region `%s` not in scope here",
bound_region_to_str(self.tcx(), br)))
result::Err(RegionError {
msg: fmt!("named region `%s` not in scope here",
bound_region_to_str(self.tcx(), br)),
replacement: self.infcx().next_region_var_nb(span)
})
}
}
}
......@@ -670,16 +675,16 @@ fn search_in_scope_regions(
}
impl region_scope for FnCtxt {
fn anon_region(&self, span: span) -> Result<ty::Region, ~str> {
fn anon_region(&self, span: span) -> Result<ty::Region, RegionError> {
result::Ok(self.infcx().next_region_var_nb(span))
}
fn self_region(&self, _span: span) -> Result<ty::Region, ~str> {
self.search_in_scope_regions(ty::br_self)
fn self_region(&self, span: span) -> Result<ty::Region, RegionError> {
self.search_in_scope_regions(span, ty::br_self)
}
fn named_region(&self,
_span: span,
id: ast::ident) -> Result<ty::Region, ~str> {
self.search_in_scope_regions(ty::br_named(id))
span: span,
id: ast::ident) -> Result<ty::Region, RegionError> {
self.search_in_scope_regions(span, ty::br_named(id))
}
}
......
......@@ -17,24 +17,33 @@
use syntax::ast;
use syntax::codemap::span;
pub struct RegionError {
msg: ~str,
replacement: ty::Region
}
pub trait region_scope {
fn anon_region(&self, span: span) -> Result<ty::Region, ~str>;
fn self_region(&self, span: span) -> Result<ty::Region, ~str>;
fn anon_region(&self, span: span) -> Result<ty::Region, RegionError>;
fn self_region(&self, span: span) -> Result<ty::Region, RegionError>;
fn named_region(&self, span: span, id: ast::ident)
-> Result<ty::Region, ~str>;
-> Result<ty::Region, RegionError>;
}
pub enum empty_rscope { empty_rscope }
impl region_scope for empty_rscope {
fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
result::Err(~"only the static region is allowed here")
fn anon_region(&self, _span: span) -> Result<ty::Region, RegionError> {
result::Err(RegionError {
msg: ~"only 'static is allowed here",
replacement: ty::re_static
})
}
fn self_region(&self, _span: span) -> Result<ty::Region, ~str> {
result::Err(~"only the static region is allowed here")
fn self_region(&self, _span: span) -> Result<ty::Region, RegionError> {
self.anon_region(_span)
}
fn named_region(&self, _span: span, _id: ast::ident)
-> Result<ty::Region, ~str> {
result::Err(~"only the static region is allowed here")
-> Result<ty::Region, RegionError>
{
self.anon_region(_span)
}
}
......@@ -43,38 +52,59 @@ pub struct MethodRscope {
region_parameterization: Option<ty::region_variance>
}
impl region_scope for MethodRscope {
fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
result::Err(~"anonymous region types are not permitted here")
fn anon_region(&self, _span: span) -> Result<ty::Region, RegionError> {
result::Err(RegionError {
msg: ~"anonymous lifetimes are not permitted here",
replacement: ty::re_bound(ty::br_self)
})
}
fn self_region(&self, _span: span) -> Result<ty::Region, ~str> {
fn self_region(&self, _span: span) -> Result<ty::Region, RegionError> {
assert self.region_parameterization.is_some() ||
self.self_ty.is_borrowed();
result::Ok(ty::re_bound(ty::br_self))
}
fn named_region(&self, span: span, id: ast::ident)
-> Result<ty::Region, ~str> {
-> Result<ty::Region, RegionError> {
do empty_rscope.named_region(span, id).chain_err |_e| {
result::Err(~"region is not in scope here")
result::Err(RegionError {
msg: ~"lifetime is not in scope",
replacement: ty::re_bound(ty::br_self)
})
}
}
}
pub enum type_rscope = Option<ty::region_variance>;
impl type_rscope {
priv fn replacement(&self) -> ty::Region {
if self.is_some() {
ty::re_bound(ty::br_self)
} else {
ty::re_static
}
}
}
impl region_scope for type_rscope {
fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
result::Err(~"anonymous region types are not permitted here")
fn anon_region(&self, _span: span) -> Result<ty::Region, RegionError> {
result::Err(RegionError {
msg: ~"anonymous lifetimes are not permitted here",
replacement: self.replacement()
})
}
fn self_region(&self, _span: span) -> Result<ty::Region, ~str> {
fn self_region(&self, _span: span) -> Result<ty::Region, RegionError> {
// if the self region is used, region parameterization should
// have inferred that this type is RP
assert self.is_some();
result::Ok(ty::re_bound(ty::br_self))
}
fn named_region(&self, span: span, id: ast::ident)
-> Result<ty::Region, ~str> {
-> Result<ty::Region, RegionError> {
do empty_rscope.named_region(span, id).chain_err |_e| {
result::Err(~"named regions other than `self` are not \
allowed as part of a type declaration")
result::Err(RegionError {
msg: ~"only 'self is allowed allowed as \
part of a type declaration",
replacement: self.replacement()
})
}
}
}
......@@ -98,17 +128,17 @@ pub fn in_binding_rscope<RS:region_scope + Copy + Durable>(self: &RS)
binding_rscope { base: base, anon_bindings: @mut 0 }
}
impl region_scope for binding_rscope {
fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
fn anon_region(&self, _span: span) -> Result<ty::Region, RegionError> {
let idx = *self.anon_bindings;
*self.anon_bindings += 1;
result::Ok(ty::re_bound(ty::br_anon(idx)))
}
fn self_region(&self, span: span) -> Result<ty::Region, ~str> {
fn self_region(&self, span: span) -> Result<ty::Region, RegionError> {
self.base.self_region(span)
}
fn named_region(&self,
span: span,
id: ast::ident) -> Result<ty::Region, ~str>
id: ast::ident) -> Result<ty::Region, RegionError>
{
do self.base.named_region(span, id).chain_err |_e| {
result::Ok(ty::re_bound(ty::br_named(id)))
......
......@@ -147,6 +147,10 @@ pub fn expr_to_str(e: @ast::expr, intr: @ident_interner) -> ~str {
to_str(e, print_expr, intr)
}
pub fn region_to_str(e: @ast::region, intr: @ident_interner) -> ~str {
to_str(e, |s, e| print_region(s, ~"&", e, ~""), intr)
}
pub fn tt_to_str(tt: ast::token_tree, intr: @ident_interner) -> ~str {
to_str(tt, print_tt, intr)
}
......
......@@ -8,8 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
const c_x: &'blk int = &22; //~ ERROR only the static region is allowed here
const c_y: &int = &22; //~ ERROR only the static region is allowed here
const c_x: &'blk int = &22; //~ ERROR Illegal lifetime &blk: only 'static is allowed here
const c_y: &int = &22; //~ ERROR Illegal anonymous lifetime: only 'static is allowed here
const c_z: &'static int = &22;
fn main() {
......
......@@ -10,7 +10,7 @@
enum yes0<'lt> {
// This will eventually be legal (and in fact the only way):
X3(&'lt uint) //~ ERROR named regions other than `self` are not allowed as part of a type declaration
X3(&'lt uint) //~ ERROR Illegal lifetime &lt: only 'self is allowed allowed as part of a type declaration
}
enum yes1 {
......@@ -18,7 +18,7 @@ enum yes1 {
}
enum yes2 {
X5(&'foo uint) //~ ERROR named regions other than `self` are not allowed as part of a type declaration
X5(&'foo uint) //~ ERROR Illegal lifetime &foo: only 'self is allowed allowed as part of a type declaration
}
fn main() {}
......@@ -9,7 +9,7 @@
// except according to those terms.
struct yes0<'self> {
x: &uint, //~ ERROR anonymous region types are not permitted here
x: &uint, //~ ERROR Illegal anonymous lifetime: anonymous lifetimes are not permitted here
}
struct yes1<'self> {
......@@ -17,7 +17,7 @@ struct yes1<'self> {
}
struct yes2<'self> {
x: &'foo uint, //~ ERROR named regions other than `self` are not allowed as part of a type declaration
x: &'foo uint, //~ ERROR Illegal lifetime &foo: only 'self is allowed allowed as part of a type declaration
}
fn main() {}
......@@ -9,7 +9,7 @@
// except according to those terms.
type item_ty_yes0 = {
x: &uint //~ ERROR anonymous region types are not permitted here
x: &uint //~ ERROR Illegal anonymous lifetime: anonymous lifetimes are not permitted here
};
type item_ty_yes1 = {
......@@ -17,7 +17,7 @@
};
type item_ty_yes2 = {
x: &'foo uint //~ ERROR named regions other than `self` are not allowed as part of a type declaration
x: &'foo uint //~ ERROR Illegal lifetime &foo: only 'self is allowed allowed as part of a type declaration
};
fn main() {}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册