Improve error messages when illegal lifetimes are used
This commit is contained in:
@@ -58,14 +58,14 @@ use middle::ty::{arg, field, substs};
|
|||||||
use middle::ty::{ty_param_substs_and_ty};
|
use middle::ty::{ty_param_substs_and_ty};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck::rscope::{in_binding_rscope};
|
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 middle::typeck::{CrateCtxt, write_substs_to_tcx, write_ty_to_tcx};
|
||||||
|
|
||||||
use core::result;
|
use core::result;
|
||||||
use core::vec;
|
use core::vec;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::codemap::span;
|
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;
|
use util::common::indenter;
|
||||||
|
|
||||||
pub trait AstConv {
|
pub trait AstConv {
|
||||||
@@ -76,17 +76,31 @@ pub trait AstConv {
|
|||||||
fn ty_infer(&self, span: span) -> ty::t;
|
fn ty_infer(&self, span: span) -> ty::t;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_region_reporting_err(tcx: ty::ctxt,
|
pub fn get_region_reporting_err(
|
||||||
span: span,
|
tcx: ty::ctxt,
|
||||||
res: Result<ty::Region, ~str>)
|
span: span,
|
||||||
-> ty::Region {
|
a_r: Option<@ast::region>,
|
||||||
|
res: Result<ty::Region, RegionError>) -> ty::Region
|
||||||
|
{
|
||||||
match res {
|
match res {
|
||||||
result::Ok(r) => r,
|
result::Ok(r) => r,
|
||||||
result::Err(ref e) => {
|
result::Err(ref e) => {
|
||||||
tcx.sess.span_err(span, (/*bad*/copy *e));
|
let descr = match a_r {
|
||||||
ty::re_static
|
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)
|
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>(
|
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) => {
|
(Some(_), None) => {
|
||||||
let res = rscope.anon_region(path.span);
|
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(r)
|
||||||
}
|
}
|
||||||
(Some(_), Some(r)) => {
|
(Some(_), Some(r)) => {
|
||||||
@@ -521,7 +535,7 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + Durable>(
|
|||||||
ast::BorrowedSigil => {
|
ast::BorrowedSigil => {
|
||||||
// &fn() defaults to an anonymous region:
|
// &fn() defaults to an anonymous region:
|
||||||
let r_result = rscope.anon_region(span);
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
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
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
//
|
//
|
||||||
@@ -96,6 +96,7 @@ use middle::typeck::CrateCtxt;
|
|||||||
use middle::typeck::infer::{resolve_type, force_tvar};
|
use middle::typeck::infer::{resolve_type, force_tvar};
|
||||||
use middle::typeck::infer;
|
use middle::typeck::infer;
|
||||||
use middle::typeck::rscope::{binding_rscope, bound_self_region};
|
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::{in_binding_rscope, region_scope, type_rscope};
|
||||||
use middle::typeck::rscope;
|
use middle::typeck::rscope;
|
||||||
use middle::typeck::{isr_alist, lookup_def_ccx, method_map_entry};
|
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 infcx(&self) -> @mut infer::InferCtxt { self.inh.infcx }
|
||||||
fn search_in_scope_regions(
|
fn search_in_scope_regions(
|
||||||
&self,
|
&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;
|
let in_scope_regions = self.in_scope_regions;
|
||||||
match in_scope_regions.find(br) {
|
match in_scope_regions.find(br) {
|
||||||
@@ -661,8 +663,11 @@ pub impl FnCtxt {
|
|||||||
if br == blk_br {
|
if br == blk_br {
|
||||||
result::Ok(self.block_region())
|
result::Ok(self.block_region())
|
||||||
} else {
|
} else {
|
||||||
result::Err(fmt!("named region `%s` not in scope here",
|
result::Err(RegionError {
|
||||||
bound_region_to_str(self.tcx(), br)))
|
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 @@ pub impl FnCtxt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl region_scope for FnCtxt {
|
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))
|
result::Ok(self.infcx().next_region_var_nb(span))
|
||||||
}
|
}
|
||||||
fn self_region(&self, _span: span) -> Result<ty::Region, ~str> {
|
fn self_region(&self, span: span) -> Result<ty::Region, RegionError> {
|
||||||
self.search_in_scope_regions(ty::br_self)
|
self.search_in_scope_regions(span, ty::br_self)
|
||||||
}
|
}
|
||||||
fn named_region(&self,
|
fn named_region(&self,
|
||||||
_span: span,
|
span: span,
|
||||||
id: ast::ident) -> Result<ty::Region, ~str> {
|
id: ast::ident) -> Result<ty::Region, RegionError> {
|
||||||
self.search_in_scope_regions(ty::br_named(id))
|
self.search_in_scope_regions(span, ty::br_named(id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,24 +17,33 @@ use core::result;
|
|||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::codemap::span;
|
use syntax::codemap::span;
|
||||||
|
|
||||||
|
pub struct RegionError {
|
||||||
|
msg: ~str,
|
||||||
|
replacement: ty::Region
|
||||||
|
}
|
||||||
|
|
||||||
pub trait region_scope {
|
pub trait region_scope {
|
||||||
fn anon_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, ~str>;
|
fn self_region(&self, span: span) -> Result<ty::Region, RegionError>;
|
||||||
fn named_region(&self, span: span, id: ast::ident)
|
fn named_region(&self, span: span, id: ast::ident)
|
||||||
-> Result<ty::Region, ~str>;
|
-> Result<ty::Region, RegionError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum empty_rscope { empty_rscope }
|
pub enum empty_rscope { empty_rscope }
|
||||||
impl region_scope for empty_rscope {
|
impl region_scope for empty_rscope {
|
||||||
fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
|
fn anon_region(&self, _span: span) -> Result<ty::Region, RegionError> {
|
||||||
result::Err(~"only the static region is allowed here")
|
result::Err(RegionError {
|
||||||
|
msg: ~"only 'static is allowed here",
|
||||||
|
replacement: ty::re_static
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn self_region(&self, _span: span) -> Result<ty::Region, ~str> {
|
fn self_region(&self, _span: span) -> Result<ty::Region, RegionError> {
|
||||||
result::Err(~"only the static region is allowed here")
|
self.anon_region(_span)
|
||||||
}
|
}
|
||||||
fn named_region(&self, _span: span, _id: ast::ident)
|
fn named_region(&self, _span: span, _id: ast::ident)
|
||||||
-> Result<ty::Region, ~str> {
|
-> Result<ty::Region, RegionError>
|
||||||
result::Err(~"only the static region is allowed here")
|
{
|
||||||
|
self.anon_region(_span)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,38 +52,59 @@ pub struct MethodRscope {
|
|||||||
region_parameterization: Option<ty::region_variance>
|
region_parameterization: Option<ty::region_variance>
|
||||||
}
|
}
|
||||||
impl region_scope for MethodRscope {
|
impl region_scope for MethodRscope {
|
||||||
fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
|
fn anon_region(&self, _span: span) -> Result<ty::Region, RegionError> {
|
||||||
result::Err(~"anonymous region types are not permitted here")
|
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() ||
|
assert self.region_parameterization.is_some() ||
|
||||||
self.self_ty.is_borrowed();
|
self.self_ty.is_borrowed();
|
||||||
result::Ok(ty::re_bound(ty::br_self))
|
result::Ok(ty::re_bound(ty::br_self))
|
||||||
}
|
}
|
||||||
fn named_region(&self, span: span, id: ast::ident)
|
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| {
|
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>;
|
pub enum type_rscope = Option<ty::region_variance>;
|
||||||
impl region_scope for type_rscope {
|
impl type_rscope {
|
||||||
fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
|
priv fn replacement(&self) -> ty::Region {
|
||||||
result::Err(~"anonymous region types are not permitted here")
|
if self.is_some() {
|
||||||
|
ty::re_bound(ty::br_self)
|
||||||
|
} else {
|
||||||
|
ty::re_static
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn self_region(&self, _span: span) -> Result<ty::Region, ~str> {
|
}
|
||||||
|
impl region_scope for type_rscope {
|
||||||
|
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, RegionError> {
|
||||||
// if the self region is used, region parameterization should
|
// if the self region is used, region parameterization should
|
||||||
// have inferred that this type is RP
|
// have inferred that this type is RP
|
||||||
assert self.is_some();
|
assert self.is_some();
|
||||||
result::Ok(ty::re_bound(ty::br_self))
|
result::Ok(ty::re_bound(ty::br_self))
|
||||||
}
|
}
|
||||||
fn named_region(&self, span: span, id: ast::ident)
|
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| {
|
do empty_rscope.named_region(span, id).chain_err |_e| {
|
||||||
result::Err(~"named regions other than `self` are not \
|
result::Err(RegionError {
|
||||||
allowed as part of a type declaration")
|
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 }
|
binding_rscope { base: base, anon_bindings: @mut 0 }
|
||||||
}
|
}
|
||||||
impl region_scope for binding_rscope {
|
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;
|
let idx = *self.anon_bindings;
|
||||||
*self.anon_bindings += 1;
|
*self.anon_bindings += 1;
|
||||||
result::Ok(ty::re_bound(ty::br_anon(idx)))
|
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)
|
self.base.self_region(span)
|
||||||
}
|
}
|
||||||
fn named_region(&self,
|
fn named_region(&self,
|
||||||
span: span,
|
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| {
|
do self.base.named_region(span, id).chain_err |_e| {
|
||||||
result::Ok(ty::re_bound(ty::br_named(id)))
|
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)
|
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 {
|
pub fn tt_to_str(tt: ast::token_tree, intr: @ident_interner) -> ~str {
|
||||||
to_str(tt, print_tt, intr)
|
to_str(tt, print_tt, intr)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
const c_x: &'blk 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 only the static region is allowed here
|
const c_y: &int = &22; //~ ERROR Illegal anonymous lifetime: only 'static is allowed here
|
||||||
const c_z: &'static int = &22;
|
const c_z: &'static int = &22;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
enum yes0<'lt> {
|
enum yes0<'lt> {
|
||||||
// This will eventually be legal (and in fact the only way):
|
// 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 <: only 'self is allowed allowed as part of a type declaration
|
||||||
}
|
}
|
||||||
|
|
||||||
enum yes1 {
|
enum yes1 {
|
||||||
@@ -18,7 +18,7 @@ enum yes1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum yes2 {
|
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() {}
|
fn main() {}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
struct yes0<'self> {
|
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> {
|
struct yes1<'self> {
|
||||||
@@ -17,7 +17,7 @@ struct yes1<'self> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct yes2<'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() {}
|
fn main() {}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
type item_ty_yes0 = {
|
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 = {
|
type item_ty_yes1 = {
|
||||||
@@ -17,7 +17,7 @@ type item_ty_yes1 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type item_ty_yes2 = {
|
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() {}
|
fn main() {}
|
||||||
|
|||||||
Reference in New Issue
Block a user