1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
16 use syntax::codemap::span;
17 use syntax::opt_vec::OptVec;
19 use syntax::parse::token::special_idents;
22 pub struct RegionError {
24 replacement: ty::Region
27 pub trait region_scope {
28 fn anon_region(&self, span: span) -> Result<ty::Region, RegionError>;
29 fn self_region(&self, span: span) -> Result<ty::Region, RegionError>;
30 fn named_region(&self, span: span, id: ast::ident)
31 -> Result<ty::Region, RegionError>;
35 pub enum empty_rscope { empty_rscope }
36 impl region_scope for empty_rscope {
37 fn anon_region(&self, _span: span) -> Result<ty::Region, RegionError> {
38 result::Err(RegionError {
39 msg: ~"only 'static is allowed here",
40 replacement: ty::re_static
43 fn self_region(&self, _span: span) -> Result<ty::Region, RegionError> {
44 self.anon_region(_span)
46 fn named_region(&self, _span: span, _id: ast::ident)
47 -> Result<ty::Region, RegionError>
49 self.anon_region(_span)
54 pub struct RegionParamNames(OptVec<ast::ident>);
56 impl RegionParamNames {
57 fn has_self(&self) -> bool {
58 self.has_ident(special_idents::self_)
61 fn has_ident(&self, ident: ast::ident) -> bool {
62 for region_param_name in self.iter() {
63 if *region_param_name == ident {
70 pub fn add_generics(&mut self, generics: &ast::Generics) {
71 match generics.lifetimes {
73 opt_vec::Vec(ref new_lifetimes) => {
76 *self = RegionParamNames(
77 opt_vec::Vec(new_lifetimes.map(|lt| lt.ident)));
79 opt_vec::Vec(ref mut existing_lifetimes) => {
80 for new_lifetime in new_lifetimes.iter() {
81 existing_lifetimes.push(new_lifetime.ident);
89 // Convenience function to produce the error for an unresolved name. The
90 // optional argument specifies a custom replacement.
91 pub fn undeclared_name(custom_replacement: Option<ty::Region>)
92 -> Result<ty::Region, RegionError> {
93 let replacement = match custom_replacement {
94 None => ty::re_bound(ty::br_self),
95 Some(custom_replacement) => custom_replacement
98 msg: ~"this lifetime must be declared",
99 replacement: replacement
103 pub fn from_generics(generics: &ast::Generics) -> RegionParamNames {
104 match generics.lifetimes {
105 opt_vec::Empty => RegionParamNames(opt_vec::Empty),
106 opt_vec::Vec(ref lifetimes) => {
107 RegionParamNames(opt_vec::Vec(lifetimes.map(|lt| lt.ident)))
112 pub fn from_lifetimes(lifetimes: &opt_vec::OptVec<ast::Lifetime>)
113 -> RegionParamNames {
115 opt_vec::Empty => RegionParamNames::new(),
116 opt_vec::Vec(ref v) => {
117 RegionParamNames(opt_vec::Vec(v.map(|lt| lt.ident)))
122 fn new() -> RegionParamNames {
123 RegionParamNames(opt_vec::Empty)
128 struct RegionParameterization {
129 variance: ty::region_variance,
130 region_param_names: RegionParamNames,
133 impl RegionParameterization {
134 pub fn from_variance_and_generics(variance: Option<ty::region_variance>,
135 generics: &ast::Generics)
136 -> Option<RegionParameterization> {
140 Some(RegionParameterization {
143 RegionParamNames::from_generics(generics),
151 pub struct MethodRscope {
152 explicit_self: ast::explicit_self_,
153 variance: Option<ty::region_variance>,
154 region_param_names: RegionParamNames,
158 // `generics` here refers to the generics of the outer item (impl or
160 pub fn new(explicit_self: ast::explicit_self_,
161 variance: Option<ty::region_variance>,
162 rcvr_generics: &ast::Generics)
164 let region_param_names =
165 RegionParamNames::from_generics(rcvr_generics);
167 explicit_self: explicit_self,
169 region_param_names: region_param_names
173 pub fn region_param_names(&self) -> RegionParamNames {
174 self.region_param_names.clone()
178 impl region_scope for MethodRscope {
179 fn anon_region(&self, _span: span) -> Result<ty::Region, RegionError> {
180 result::Err(RegionError {
181 msg: ~"anonymous lifetimes are not permitted here",
182 replacement: ty::re_bound(ty::br_self)
185 fn self_region(&self, _span: span) -> Result<ty::Region, RegionError> {
186 assert!(self.variance.is_some());
187 match self.variance {
188 None => {} // must be borrowed self, so this is OK
190 if !self.region_param_names.has_self() {
191 return Err(RegionError {
192 msg: ~"the `self` lifetime must be declared",
193 replacement: ty::re_bound(ty::br_self)
198 result::Ok(ty::re_bound(ty::br_self))
200 fn named_region(&self, span: span, id: ast::ident)
201 -> Result<ty::Region, RegionError> {
202 if !self.region_param_names.has_ident(id) {
203 return RegionParamNames::undeclared_name(None);
205 do empty_rscope.named_region(span, id).chain_err |_e| {
206 result::Err(RegionError {
207 msg: ~"lifetime is not in scope",
208 replacement: ty::re_bound(ty::br_self)
215 pub struct type_rscope(Option<RegionParameterization>);
218 priv fn replacement(&self) -> ty::Region {
220 ty::re_bound(ty::br_self)
226 impl region_scope for type_rscope {
227 fn anon_region(&self, _span: span) -> Result<ty::Region, RegionError> {
228 result::Err(RegionError {
229 msg: ~"anonymous lifetimes are not permitted here",
230 replacement: self.replacement()
233 fn self_region(&self, _span: span) -> Result<ty::Region, RegionError> {
236 // if the self region is used, region parameterization should
237 // have inferred that this type is RP
238 fail!("region parameterization should have inferred that \
241 Some(ref region_parameterization) => {
242 if !region_parameterization.region_param_names.has_self() {
243 return Err(RegionError {
244 msg: ~"the `self` lifetime must be declared",
245 replacement: ty::re_bound(ty::br_self)
250 result::Ok(ty::re_bound(ty::br_self))
252 fn named_region(&self, span: span, id: ast::ident)
253 -> Result<ty::Region, RegionError> {
254 do empty_rscope.named_region(span, id).chain_err |_e| {
255 result::Err(RegionError {
256 msg: ~"only 'self is allowed as part of a type declaration",
257 replacement: self.replacement()
263 pub fn bound_self_region(rp: Option<ty::region_variance>)
264 -> OptVec<ty::Region> {
266 Some(_) => opt_vec::with(ty::re_bound(ty::br_self)),
267 None => opt_vec::Empty
271 pub struct binding_rscope {
273 anon_bindings: @mut uint,
274 region_param_names: RegionParamNames,
277 impl Clone for binding_rscope {
278 fn clone(&self) -> binding_rscope {
281 anon_bindings: self.anon_bindings,
282 region_param_names: self.region_param_names.clone(),
287 pub fn in_binding_rscope<RS:region_scope + Clone + 'static>(
289 region_param_names: RegionParamNames)
291 let base = @(*this).clone();
292 let base = base as @region_scope;
295 anon_bindings: @mut 0,
296 region_param_names: region_param_names,
300 impl region_scope for binding_rscope {
301 fn anon_region(&self, _span: span) -> Result<ty::Region, RegionError> {
302 let idx = *self.anon_bindings;
303 *self.anon_bindings += 1;
304 result::Ok(ty::re_bound(ty::br_anon(idx)))
306 fn self_region(&self, span: span) -> Result<ty::Region, RegionError> {
307 self.base.self_region(span)
309 fn named_region(&self,
311 id: ast::ident) -> Result<ty::Region, RegionError>
313 do self.base.named_region(span, id).chain_err |_e| {
314 let result = ty::re_bound(ty::br_named(id));
315 if self.region_param_names.has_ident(id) {
318 RegionParamNames::undeclared_name(Some(result))