]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/typeck/rscope.rs
Fix bug in `match`ing struct patterns
[rust.git] / src / librustc / middle / typeck / rscope.rs
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.
4 //
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.
10
11
12 use middle::ty;
13
14 use std::result;
15 use syntax::ast;
16 use syntax::codemap::span;
17 use syntax::opt_vec::OptVec;
18 use syntax::opt_vec;
19 use syntax::parse::token::special_idents;
20
21 #[deriving(ToStr)]
22 pub struct RegionError {
23     msg: ~str,
24     replacement: ty::Region
25 }
26
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>;
32 }
33
34 #[deriving(Clone)]
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
41         })
42     }
43     fn self_region(&self, _span: span) -> Result<ty::Region, RegionError> {
44         self.anon_region(_span)
45     }
46     fn named_region(&self, _span: span, _id: ast::ident)
47         -> Result<ty::Region, RegionError>
48     {
49         self.anon_region(_span)
50     }
51 }
52
53 #[deriving(Clone)]
54 pub struct RegionParamNames(OptVec<ast::ident>);
55
56 impl RegionParamNames {
57     fn has_self(&self) -> bool {
58         self.has_ident(special_idents::self_)
59     }
60
61     fn has_ident(&self, ident: ast::ident) -> bool {
62         for region_param_name in self.iter() {
63             if *region_param_name == ident {
64                 return true;
65             }
66         }
67         false
68     }
69
70     pub fn add_generics(&mut self, generics: &ast::Generics) {
71         match generics.lifetimes {
72             opt_vec::Empty => {}
73             opt_vec::Vec(ref new_lifetimes) => {
74                 match **self {
75                     opt_vec::Empty => {
76                         *self = RegionParamNames(
77                             opt_vec::Vec(new_lifetimes.map(|lt| lt.ident)));
78                     }
79                     opt_vec::Vec(ref mut existing_lifetimes) => {
80                         for new_lifetime in new_lifetimes.iter() {
81                             existing_lifetimes.push(new_lifetime.ident);
82                         }
83                     }
84                 }
85             }
86         }
87     }
88
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
96         };
97         Err(RegionError {
98             msg: ~"this lifetime must be declared",
99             replacement: replacement
100         })
101     }
102
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)))
108             }
109         }
110     }
111
112     pub fn from_lifetimes(lifetimes: &opt_vec::OptVec<ast::Lifetime>)
113                        -> RegionParamNames {
114         match *lifetimes {
115             opt_vec::Empty => RegionParamNames::new(),
116             opt_vec::Vec(ref v) => {
117                 RegionParamNames(opt_vec::Vec(v.map(|lt| lt.ident)))
118             }
119         }
120     }
121
122     fn new() -> RegionParamNames {
123         RegionParamNames(opt_vec::Empty)
124     }
125 }
126
127 #[deriving(Clone)]
128 struct RegionParameterization {
129     variance: ty::region_variance,
130     region_param_names: RegionParamNames,
131 }
132
133 impl RegionParameterization {
134     pub fn from_variance_and_generics(variance: Option<ty::region_variance>,
135                                       generics: &ast::Generics)
136                                    -> Option<RegionParameterization> {
137         match variance {
138             None => None,
139             Some(variance) => {
140                 Some(RegionParameterization {
141                     variance: variance,
142                     region_param_names:
143                         RegionParamNames::from_generics(generics),
144                 })
145             }
146         }
147     }
148 }
149
150 #[deriving(Clone)]
151 pub struct MethodRscope {
152     explicit_self: ast::explicit_self_,
153     variance: Option<ty::region_variance>,
154     region_param_names: RegionParamNames,
155 }
156
157 impl MethodRscope {
158     // `generics` here refers to the generics of the outer item (impl or
159     // trait).
160     pub fn new(explicit_self: ast::explicit_self_,
161                variance: Option<ty::region_variance>,
162                rcvr_generics: &ast::Generics)
163             -> MethodRscope {
164         let region_param_names =
165             RegionParamNames::from_generics(rcvr_generics);
166         MethodRscope {
167             explicit_self: explicit_self,
168             variance: variance,
169             region_param_names: region_param_names
170         }
171     }
172
173     pub fn region_param_names(&self) -> RegionParamNames {
174         self.region_param_names.clone()
175     }
176 }
177
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)
183         })
184     }
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
189             Some(_) => {
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)
194                     })
195                 }
196             }
197         }
198         result::Ok(ty::re_bound(ty::br_self))
199     }
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);
204         }
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)
209             })
210         }
211     }
212 }
213
214 #[deriving(Clone)]
215 pub struct type_rscope(Option<RegionParameterization>);
216
217 impl type_rscope {
218     priv fn replacement(&self) -> ty::Region {
219         if self.is_some() {
220             ty::re_bound(ty::br_self)
221         } else {
222             ty::re_static
223         }
224     }
225 }
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()
231         })
232     }
233     fn self_region(&self, _span: span) -> Result<ty::Region, RegionError> {
234         match **self {
235             None => {
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 \
239                         this type is RP");
240             }
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)
246                     })
247                 }
248             }
249         }
250         result::Ok(ty::re_bound(ty::br_self))
251     }
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()
258             })
259         }
260     }
261 }
262
263 pub fn bound_self_region(rp: Option<ty::region_variance>)
264                       -> OptVec<ty::Region> {
265     match rp {
266       Some(_) => opt_vec::with(ty::re_bound(ty::br_self)),
267       None => opt_vec::Empty
268     }
269 }
270
271 pub struct binding_rscope {
272     base: @region_scope,
273     anon_bindings: @mut uint,
274     region_param_names: RegionParamNames,
275 }
276
277 impl Clone for binding_rscope {
278     fn clone(&self) -> binding_rscope {
279         binding_rscope {
280             base: self.base,
281             anon_bindings: self.anon_bindings,
282             region_param_names: self.region_param_names.clone(),
283         }
284     }
285 }
286
287 pub fn in_binding_rscope<RS:region_scope + Clone + 'static>(
288         this: &RS,
289         region_param_names: RegionParamNames)
290      -> binding_rscope {
291     let base = @(*this).clone();
292     let base = base as @region_scope;
293     binding_rscope {
294         base: base,
295         anon_bindings: @mut 0,
296         region_param_names: region_param_names,
297     }
298 }
299
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)))
305     }
306     fn self_region(&self, span: span) -> Result<ty::Region, RegionError> {
307         self.base.self_region(span)
308     }
309     fn named_region(&self,
310                     span: span,
311                     id: ast::ident) -> Result<ty::Region, RegionError>
312     {
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) {
316                 result::Ok(result)
317             } else {
318                 RegionParamNames::undeclared_name(Some(result))
319             }
320         }
321     }
322 }