]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/rscope.rs
839eb8be9ace8c093ccaa115e4a174acab0e0fc4
[rust.git] / src / librustc_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 use rustc::hir;
12 use rustc::hir::def_id::DefId;
13 use rustc::ty;
14 use rustc::ty::subst::Substs;
15
16 use astconv::AstConv;
17
18 use std::cell::Cell;
19 use syntax_pos::Span;
20
21 #[derive(Clone)]
22 pub struct ElisionFailureInfo {
23     /// Where we can find the argument pattern.
24     pub parent: Option<hir::BodyId>,
25     /// The index of the argument in the original definition.
26     pub index: usize,
27     pub lifetime_count: usize,
28     pub have_bound_regions: bool
29 }
30
31 pub type ElidedLifetime = Result<ty::Region, Option<Vec<ElisionFailureInfo>>>;
32
33 /// Defines strategies for handling regions that are omitted.  For
34 /// example, if one writes the type `&Foo`, then the lifetime of
35 /// this reference has been omitted. When converting this
36 /// type, the generic functions in astconv will invoke `anon_region`
37 /// on the provided region-scope to decide how to translate this
38 /// omitted region.
39 ///
40 /// It is not always legal to omit regions, therefore `anon_region`
41 /// can return `Err(())` to indicate that this is not a scope in which
42 /// regions can legally be omitted.
43 pub trait RegionScope {
44     fn anon_region(&self, span: Span)
45                     -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>>;
46
47     /// If an object omits any explicit lifetime bound, and none can
48     /// be derived from the object traits, what should we use? If
49     /// `None` is returned, an explicit annotation is required.
50     fn object_lifetime_default(&self, span: Span) -> Option<ty::Region>;
51
52     /// The "base" default is the initial default for a scope. This is
53     /// 'static except for in fn bodies, where it is a fresh inference
54     /// variable. You shouldn't call this except for as part of
55     /// computing `object_lifetime_default` (in particular, in legacy
56     /// modes, it may not be relevant).
57     fn base_object_lifetime_default(&self, span: Span) -> ty::Region;
58
59     /// If this scope allows anonymized types, return the generics in
60     /// scope, that anonymized types will close over. For example,
61     /// if you have a function like:
62     ///
63     ///     fn foo<'a, T>() -> impl Trait { ... }
64     ///
65     /// then, for the rscope that is used when handling the return type,
66     /// `anon_type_scope()` would return a `Some(AnonTypeScope {...})`,
67     /// on which `.fresh_substs(...)` can be used to obtain identity
68     /// Substs for `'a` and `T`, to track them in `TyAnon`. This property
69     /// is controlled by the region scope because it's fine-grained enough
70     /// to allow restriction of anonymized types to the syntactical extent
71     /// of a function's return type.
72     fn anon_type_scope(&self) -> Option<AnonTypeScope> {
73         None
74     }
75 }
76
77 #[derive(Copy, Clone)]
78 pub struct AnonTypeScope {
79     enclosing_item: DefId
80 }
81
82 impl<'gcx: 'tcx, 'tcx> AnonTypeScope {
83     pub fn new(enclosing_item: DefId) -> AnonTypeScope {
84         AnonTypeScope {
85             enclosing_item: enclosing_item
86         }
87     }
88
89     pub fn fresh_substs(&self, astconv: &AstConv<'gcx, 'tcx>, span: Span)
90                         -> &'tcx Substs<'tcx> {
91         use collect::mk_item_substs;
92
93         mk_item_substs(astconv, span, self.enclosing_item)
94     }
95 }
96
97 /// A scope wrapper which optionally allows anonymized types.
98 #[derive(Copy, Clone)]
99 pub struct MaybeWithAnonTypes<R> {
100     base_scope: R,
101     anon_scope: Option<AnonTypeScope>
102 }
103
104 impl<R: RegionScope> MaybeWithAnonTypes<R>  {
105     pub fn new(base_scope: R, anon_scope: Option<AnonTypeScope>) -> Self {
106         MaybeWithAnonTypes {
107             base_scope: base_scope,
108             anon_scope: anon_scope
109         }
110     }
111 }
112
113 impl<R: RegionScope> RegionScope for MaybeWithAnonTypes<R> {
114     fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
115         self.base_scope.object_lifetime_default(span)
116     }
117
118     fn anon_region(&self, span: Span)
119                    -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>> {
120         self.base_scope.anon_region(span)
121     }
122
123     fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
124         self.base_scope.base_object_lifetime_default(span)
125     }
126
127     fn anon_type_scope(&self) -> Option<AnonTypeScope> {
128         self.anon_scope
129     }
130 }
131
132 // A scope in which all regions must be explicitly named. This is used
133 // for types that appear in structs and so on.
134 #[derive(Copy, Clone)]
135 pub struct ExplicitRscope;
136
137 impl RegionScope for ExplicitRscope {
138     fn anon_region(&self, _span: Span)
139                    -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>> {
140         Err(None)
141     }
142
143     fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
144         Some(self.base_object_lifetime_default(span))
145     }
146
147     fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
148         ty::ReStatic
149     }
150 }
151
152 // Same as `ExplicitRscope`, but provides some extra information for diagnostics
153 pub struct UnelidableRscope(Option<Vec<ElisionFailureInfo>>);
154
155 impl UnelidableRscope {
156     pub fn new(v: Option<Vec<ElisionFailureInfo>>) -> UnelidableRscope {
157         UnelidableRscope(v)
158     }
159 }
160
161 impl RegionScope for UnelidableRscope {
162     fn anon_region(&self, _span: Span)
163                    -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>> {
164         Err(self.0.clone())
165     }
166
167     fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
168         Some(self.base_object_lifetime_default(span))
169     }
170
171     fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
172         ty::ReStatic
173     }
174 }
175
176 // A scope in which omitted anonymous region defaults to
177 // `default`. This is used after the `->` in function signatures. The
178 // latter use may go away. Note that object-lifetime defaults work a
179 // bit differently, as specified in RFC #599.
180 pub struct ElidableRscope {
181     default: ty::Region,
182 }
183
184 impl ElidableRscope {
185     pub fn new(r: ty::Region) -> ElidableRscope {
186         ElidableRscope { default: r }
187     }
188 }
189
190 impl RegionScope for ElidableRscope {
191     fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
192         // Per RFC #599, object-lifetimes default to 'static unless
193         // overridden by context, and this takes precedence over
194         // lifetime elision.
195         Some(self.base_object_lifetime_default(span))
196     }
197
198     fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
199         ty::ReStatic
200     }
201
202     fn anon_region(&self, _span: Span)
203                    -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>>
204     {
205         Ok(self.default)
206     }
207 }
208
209 /// A scope that behaves as an ElidabeRscope with a `'static` default region
210 /// that should also warn if the `static_in_const` feature is unset.
211 #[derive(Copy, Clone)]
212 pub struct StaticRscope<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
213     tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>,
214 }
215
216 impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> StaticRscope<'a, 'gcx, 'tcx> {
217     /// create a new StaticRscope from a reference to the `TyCtxt`
218     pub fn new(tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>) -> Self {
219         StaticRscope { tcx: tcx }
220     }
221 }
222
223 impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> {
224     fn anon_region(&self, span: Span)
225                    -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>> {
226         if !self.tcx.sess.features.borrow().static_in_const {
227             self.tcx
228                 .sess
229                 .struct_span_err(span,
230                                  "this needs a `'static` lifetime or the \
231                                  `static_in_const` feature, see #35897")
232                 .emit();
233         }
234         Ok(ty::ReStatic)
235     }
236
237     fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
238         Some(self.base_object_lifetime_default(span))
239     }
240
241     fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
242         ty::ReStatic
243     }
244 }
245
246 /// A scope in which we generate anonymous, late-bound regions for
247 /// omitted regions. This occurs in function signatures.
248 pub struct BindingRscope {
249     anon_bindings: Cell<u32>,
250 }
251
252 impl BindingRscope {
253     pub fn new() -> BindingRscope {
254         BindingRscope {
255             anon_bindings: Cell::new(0),
256         }
257     }
258 }
259
260 impl RegionScope for BindingRscope {
261     fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
262         // Per RFC #599, object-lifetimes default to 'static unless
263         // overridden by context, and this takes precedence over the
264         // binding defaults in a fn signature.
265         Some(self.base_object_lifetime_default(span))
266     }
267
268     fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
269         ty::ReStatic
270     }
271
272     fn anon_region(&self, _: Span)
273                    -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>>
274     {
275         let idx = self.anon_bindings.get();
276         self.anon_bindings.set(idx + 1);
277         Ok(ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(idx)))
278     }
279 }
280
281 /// A scope which overrides the default object lifetime but has no other effect.
282 pub struct ObjectLifetimeDefaultRscope<'r> {
283     base_scope: &'r (RegionScope+'r),
284     default: ty::ObjectLifetimeDefault<'r>,
285 }
286
287 impl<'r> ObjectLifetimeDefaultRscope<'r> {
288     pub fn new(base_scope: &'r (RegionScope+'r),
289                default: ty::ObjectLifetimeDefault<'r>)
290                -> ObjectLifetimeDefaultRscope<'r>
291     {
292         ObjectLifetimeDefaultRscope {
293             base_scope: base_scope,
294             default: default,
295         }
296     }
297 }
298
299 impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> {
300     fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
301         match self.default {
302             ty::ObjectLifetimeDefault::Ambiguous =>
303                 None,
304
305             ty::ObjectLifetimeDefault::BaseDefault =>
306                 // NB: This behavior changed in Rust 1.3.
307                 Some(self.base_object_lifetime_default(span)),
308
309             ty::ObjectLifetimeDefault::Specific(r) =>
310                 Some(*r),
311         }
312     }
313
314     fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
315         self.base_scope.base_object_lifetime_default(span)
316     }
317
318     fn anon_region(&self, span: Span)
319                    -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>>
320     {
321         self.base_scope.anon_region(span)
322     }
323
324     fn anon_type_scope(&self) -> Option<AnonTypeScope> {
325         self.base_scope.anon_type_scope()
326     }
327 }
328
329 /// A scope which simply shifts the Debruijn index of other scopes
330 /// to account for binding levels.
331 pub struct ShiftedRscope<'r> {
332     base_scope: &'r (RegionScope+'r)
333 }
334
335 impl<'r> ShiftedRscope<'r> {
336     pub fn new(base_scope: &'r (RegionScope+'r)) -> ShiftedRscope<'r> {
337         ShiftedRscope { base_scope: base_scope }
338     }
339 }
340
341 impl<'r> RegionScope for ShiftedRscope<'r> {
342     fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
343         self.base_scope.object_lifetime_default(span)
344             .map(|r| ty::fold::shift_region(r, 1))
345     }
346
347     fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
348         ty::fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1)
349     }
350
351     fn anon_region(&self, span: Span)
352                    -> Result<ty::Region, Option<Vec<ElisionFailureInfo>>>
353     {
354         self.base_scope.anon_region(span).map(|r| ty::fold::shift_region(r, 1))
355     }
356
357     fn anon_type_scope(&self) -> Option<AnonTypeScope> {
358         self.base_scope.anon_type_scope()
359     }
360 }