]> git.proxmox.com Git - rustc.git/blame - src/librustc/ty/fold.rs
New upstream version 1.12.1+dfsg1
[rustc.git] / src / librustc / ty / fold.rs
CommitLineData
e9174d1e
SL
1// Copyright 2012-2013 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//! Generalized type folding mechanism. The setup is a bit convoluted
12//! but allows for convenient usage. Let T be an instance of some
13//! "foldable type" (one which implements `TypeFoldable`) and F be an
14//! instance of a "folder" (a type which implements `TypeFolder`). Then
15//! the setup is intended to be:
16//!
9cc50fc6 17//! T.fold_with(F) --calls--> F.fold_T(T) --calls--> T.super_fold_with(F)
e9174d1e
SL
18//!
19//! This way, when you define a new folder F, you can override
9cc50fc6 20//! `fold_T()` to customize the behavior, and invoke `T.super_fold_with()`
e9174d1e
SL
21//! to get the original behavior. Meanwhile, to actually fold
22//! something, you can just write `T.fold_with(F)`, which is
23//! convenient. (Note that `fold_with` will also transparently handle
24//! things like a `Vec<T>` where T is foldable and so on.)
25//!
26//! In this ideal setup, the only function that actually *does*
9cc50fc6
SL
27//! anything is `T.super_fold_with()`, which traverses the type `T`.
28//! Moreover, `T.super_fold_with()` should only ever call `T.fold_with()`.
e9174d1e
SL
29//!
30//! In some cases, we follow a degenerate pattern where we do not have
9cc50fc6
SL
31//! a `fold_T` method. Instead, `T.fold_with` traverses the structure directly.
32//! This is suboptimal because the behavior cannot be overridden, but it's
33//! much less work to implement. If you ever *do* need an override that
34//! doesn't exist, it's not hard to convert the degenerate pattern into the
35//! proper thing.
36//!
37//! A `TypeFoldable` T can also be visited by a `TypeVisitor` V using similar setup:
38//! T.visit_with(V) --calls--> V.visit_T(T) --calls--> T.super_visit_with(V).
39//! These methods return true to indicate that the visitor has found what it is looking for
40//! and does not need to visit anything else.
e9174d1e
SL
41
42use middle::region;
54a0048b
SL
43use ty::subst;
44use ty::adjustment;
45use ty::{self, Binder, Ty, TyCtxt, TypeFlags};
e9174d1e
SL
46
47use std::fmt;
48use util::nodemap::{FnvHashMap, FnvHashSet};
49
e9174d1e
SL
50/// The TypeFoldable trait is implemented for every type that can be folded.
51/// Basically, every type that has a corresponding method in TypeFolder.
52pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
a7813a04
XL
53 fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self;
54 fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
9cc50fc6
SL
55 self.super_fold_with(folder)
56 }
57
58 fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool;
59 fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
60 self.super_visit_with(visitor)
61 }
62
63 fn has_regions_escaping_depth(&self, depth: u32) -> bool {
64 self.visit_with(&mut HasEscapingRegionsVisitor { depth: depth })
65 }
66 fn has_escaping_regions(&self) -> bool {
67 self.has_regions_escaping_depth(0)
68 }
69
70 fn has_type_flags(&self, flags: TypeFlags) -> bool {
71 self.visit_with(&mut HasTypeFlagsVisitor { flags: flags })
72 }
73 fn has_projection_types(&self) -> bool {
74 self.has_type_flags(TypeFlags::HAS_PROJECTION)
75 }
76 fn references_error(&self) -> bool {
77 self.has_type_flags(TypeFlags::HAS_TY_ERR)
78 }
79 fn has_param_types(&self) -> bool {
80 self.has_type_flags(TypeFlags::HAS_PARAMS)
81 }
82 fn has_self_ty(&self) -> bool {
83 self.has_type_flags(TypeFlags::HAS_SELF)
84 }
85 fn has_infer_types(&self) -> bool {
86 self.has_type_flags(TypeFlags::HAS_TY_INFER)
87 }
88 fn needs_infer(&self) -> bool {
89 self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER)
90 }
91 fn needs_subst(&self) -> bool {
92 self.has_type_flags(TypeFlags::NEEDS_SUBST)
93 }
94 fn has_closure_types(&self) -> bool {
95 self.has_type_flags(TypeFlags::HAS_TY_CLOSURE)
96 }
97 fn has_erasable_regions(&self) -> bool {
98 self.has_type_flags(TypeFlags::HAS_RE_EARLY_BOUND |
99 TypeFlags::HAS_RE_INFER |
100 TypeFlags::HAS_FREE_REGIONS)
101 }
3157f602
XL
102 fn is_normalized_for_trans(&self) -> bool {
103 !self.has_type_flags(TypeFlags::HAS_RE_EARLY_BOUND |
104 TypeFlags::HAS_RE_INFER |
105 TypeFlags::HAS_FREE_REGIONS |
106 TypeFlags::HAS_TY_INFER |
107 TypeFlags::HAS_PARAMS |
1bb2cb6e 108 TypeFlags::HAS_NORMALIZABLE_PROJECTION |
3157f602
XL
109 TypeFlags::HAS_TY_ERR |
110 TypeFlags::HAS_SELF)
111 }
9cc50fc6
SL
112 /// Indicates whether this value references only 'global'
113 /// types/lifetimes that are the same regardless of what fn we are
114 /// in. This is used for caching. Errs on the side of returning
115 /// false.
116 fn is_global(&self) -> bool {
117 !self.has_type_flags(TypeFlags::HAS_LOCAL_NAMES)
118 }
e9174d1e
SL
119}
120
121/// The TypeFolder trait defines the actual *folding*. There is a
122/// method defined for every foldable type. Each of these has a
123/// default implementation that does an "identity" fold. Within each
124/// identity fold, it should invoke `foo.fold_with(self)` to fold each
125/// sub-item.
a7813a04
XL
126pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized {
127 fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>;
e9174d1e
SL
128
129 fn fold_binder<T>(&mut self, t: &Binder<T>) -> Binder<T>
130 where T : TypeFoldable<'tcx>
131 {
9cc50fc6 132 t.super_fold_with(self)
e9174d1e
SL
133 }
134
135 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
9cc50fc6 136 t.super_fold_with(self)
e9174d1e
SL
137 }
138
139 fn fold_mt(&mut self, t: &ty::TypeAndMut<'tcx>) -> ty::TypeAndMut<'tcx> {
9cc50fc6 140 t.super_fold_with(self)
e9174d1e
SL
141 }
142
143 fn fold_trait_ref(&mut self, t: &ty::TraitRef<'tcx>) -> ty::TraitRef<'tcx> {
9cc50fc6 144 t.super_fold_with(self)
e9174d1e
SL
145 }
146
54a0048b
SL
147 fn fold_impl_header(&mut self, imp: &ty::ImplHeader<'tcx>) -> ty::ImplHeader<'tcx> {
148 imp.super_fold_with(self)
149 }
150
e9174d1e 151 fn fold_substs(&mut self,
a7813a04
XL
152 substs: &'tcx subst::Substs<'tcx>)
153 -> &'tcx subst::Substs<'tcx> {
9cc50fc6 154 substs.super_fold_with(self)
e9174d1e
SL
155 }
156
157 fn fold_fn_sig(&mut self,
158 sig: &ty::FnSig<'tcx>)
159 -> ty::FnSig<'tcx> {
9cc50fc6 160 sig.super_fold_with(self)
e9174d1e
SL
161 }
162
e9174d1e 163 fn fold_bare_fn_ty(&mut self,
a7813a04
XL
164 fty: &'tcx ty::BareFnTy<'tcx>)
165 -> &'tcx ty::BareFnTy<'tcx>
e9174d1e 166 {
9cc50fc6 167 fty.super_fold_with(self)
e9174d1e
SL
168 }
169
170 fn fold_closure_ty(&mut self,
171 fty: &ty::ClosureTy<'tcx>)
172 -> ty::ClosureTy<'tcx> {
9cc50fc6 173 fty.super_fold_with(self)
e9174d1e
SL
174 }
175
176 fn fold_region(&mut self, r: ty::Region) -> ty::Region {
9cc50fc6 177 r.super_fold_with(self)
e9174d1e
SL
178 }
179
180 fn fold_existential_bounds(&mut self, s: &ty::ExistentialBounds<'tcx>)
181 -> ty::ExistentialBounds<'tcx> {
9cc50fc6 182 s.super_fold_with(self)
e9174d1e
SL
183 }
184
185 fn fold_autoref(&mut self, ar: &adjustment::AutoRef<'tcx>)
186 -> adjustment::AutoRef<'tcx> {
9cc50fc6 187 ar.super_fold_with(self)
e9174d1e 188 }
e9174d1e
SL
189}
190
9cc50fc6 191pub trait TypeVisitor<'tcx> : Sized {
54a0048b
SL
192 fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool {
193 t.super_visit_with(self)
194 }
e9174d1e 195
9cc50fc6
SL
196 fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
197 t.super_visit_with(self)
e9174d1e 198 }
e9174d1e 199
9cc50fc6
SL
200 fn visit_region(&mut self, r: ty::Region) -> bool {
201 r.super_visit_with(self)
e9174d1e
SL
202 }
203}
204
205///////////////////////////////////////////////////////////////////////////
206// Some sample folders
207
a7813a04
XL
208pub struct BottomUpFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a, F>
209 where F: FnMut(Ty<'tcx>) -> Ty<'tcx>
210{
211 pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
e9174d1e
SL
212 pub fldop: F,
213}
214
a7813a04
XL
215impl<'a, 'gcx, 'tcx, F> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx, F>
216 where F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
e9174d1e 217{
a7813a04 218 fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
e9174d1e
SL
219
220 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
9cc50fc6 221 let t1 = ty.super_fold_with(self);
e9174d1e
SL
222 (self.fldop)(t1)
223 }
224}
225
226///////////////////////////////////////////////////////////////////////////
227// Region folder
228
a7813a04 229impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
e9174d1e
SL
230 /// Collects the free and escaping regions in `value` into `region_set`. Returns
231 /// whether any late-bound regions were skipped
a7813a04 232 pub fn collect_regions<T>(self,
e9174d1e
SL
233 value: &T,
234 region_set: &mut FnvHashSet<ty::Region>)
235 -> bool
236 where T : TypeFoldable<'tcx>
237 {
238 let mut have_bound_regions = false;
239 self.fold_regions(value, &mut have_bound_regions,
240 |r, d| { region_set.insert(r.from_depth(d)); r });
241 have_bound_regions
242 }
243
244 /// Folds the escaping and free regions in `value` using `f`, and
245 /// sets `skipped_regions` to true if any late-bound region was found
246 /// and skipped.
a7813a04 247 pub fn fold_regions<T,F>(self,
e9174d1e
SL
248 value: &T,
249 skipped_regions: &mut bool,
250 mut f: F)
251 -> T
252 where F : FnMut(ty::Region, u32) -> ty::Region,
253 T : TypeFoldable<'tcx>,
254 {
255 value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f))
256 }
257}
258
259/// Folds over the substructure of a type, visiting its component
260/// types and all regions that occur *free* within it.
261///
262/// That is, `Ty` can contain function or method types that bind
263/// regions at the call site (`ReLateBound`), and occurrences of
264/// regions (aka "lifetimes") that are bound within a type are not
265/// visited by this folder; only regions that occur free will be
266/// visited by `fld_r`.
267
a7813a04
XL
268pub struct RegionFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
269 tcx: TyCtxt<'a, 'gcx, 'tcx>,
e9174d1e
SL
270 skipped_regions: &'a mut bool,
271 current_depth: u32,
272 fld_r: &'a mut (FnMut(ty::Region, u32) -> ty::Region + 'a),
273}
274
a7813a04
XL
275impl<'a, 'gcx, 'tcx> RegionFolder<'a, 'gcx, 'tcx> {
276 pub fn new<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
e9174d1e 277 skipped_regions: &'a mut bool,
a7813a04 278 fld_r: &'a mut F) -> RegionFolder<'a, 'gcx, 'tcx>
e9174d1e
SL
279 where F : FnMut(ty::Region, u32) -> ty::Region
280 {
281 RegionFolder {
282 tcx: tcx,
283 skipped_regions: skipped_regions,
284 current_depth: 1,
285 fld_r: fld_r,
286 }
287 }
288}
289
a7813a04
XL
290impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFolder<'a, 'gcx, 'tcx> {
291 fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
e9174d1e 292
54a0048b 293 fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
e9174d1e 294 self.current_depth += 1;
54a0048b 295 let t = t.super_fold_with(self);
e9174d1e 296 self.current_depth -= 1;
54a0048b 297 t
e9174d1e
SL
298 }
299
300 fn fold_region(&mut self, r: ty::Region) -> ty::Region {
301 match r {
302 ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => {
303 debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})",
304 r, self.current_depth);
305 *self.skipped_regions = true;
306 r
307 }
308 _ => {
309 debug!("RegionFolder.fold_region({:?}) folding free region (current_depth={})",
310 r, self.current_depth);
311 (self.fld_r)(r, self.current_depth)
312 }
313 }
314 }
315}
316
317///////////////////////////////////////////////////////////////////////////
318// Late-bound region replacer
319
320// Replaces the escaping regions in a type.
321
a7813a04
XL
322struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
323 tcx: TyCtxt<'a, 'gcx, 'tcx>,
e9174d1e
SL
324 current_depth: u32,
325 fld_r: &'a mut (FnMut(ty::BoundRegion) -> ty::Region + 'a),
326 map: FnvHashMap<ty::BoundRegion, ty::Region>
327}
328
a7813a04
XL
329impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
330 pub fn replace_late_bound_regions<T,F>(self,
e9174d1e
SL
331 value: &Binder<T>,
332 mut f: F)
333 -> (T, FnvHashMap<ty::BoundRegion, ty::Region>)
334 where F : FnMut(ty::BoundRegion) -> ty::Region,
335 T : TypeFoldable<'tcx>,
336 {
e9174d1e
SL
337 let mut replacer = RegionReplacer::new(self, &mut f);
338 let result = value.skip_binder().fold_with(&mut replacer);
339 (result, replacer.map)
340 }
341
342
343 /// Replace any late-bound regions bound in `value` with free variants attached to scope-id
344 /// `scope_id`.
a7813a04 345 pub fn liberate_late_bound_regions<T>(self,
e9174d1e
SL
346 all_outlive_scope: region::CodeExtent,
347 value: &Binder<T>)
348 -> T
349 where T : TypeFoldable<'tcx>
350 {
351 self.replace_late_bound_regions(value, |br| {
352 ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})
353 }).0
354 }
355
356 /// Flattens two binding levels into one. So `for<'a> for<'b> Foo`
357 /// becomes `for<'a,'b> Foo`.
a7813a04 358 pub fn flatten_late_bound_regions<T>(self, bound2_value: &Binder<Binder<T>>)
e9174d1e
SL
359 -> Binder<T>
360 where T: TypeFoldable<'tcx>
361 {
362 let bound0_value = bound2_value.skip_binder().skip_binder();
363 let value = self.fold_regions(bound0_value, &mut false,
364 |region, current_depth| {
365 match region {
366 ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => {
367 // should be true if no escaping regions from bound2_value
368 assert!(debruijn.depth - current_depth <= 1);
369 ty::ReLateBound(ty::DebruijnIndex::new(current_depth), br)
370 }
371 _ => {
372 region
373 }
374 }
375 });
376 Binder(value)
377 }
378
a7813a04 379 pub fn no_late_bound_regions<T>(self, value: &Binder<T>) -> Option<T>
9cc50fc6 380 where T : TypeFoldable<'tcx>
e9174d1e
SL
381 {
382 if value.0.has_escaping_regions() {
383 None
384 } else {
385 Some(value.0.clone())
386 }
387 }
388
a7813a04
XL
389 /// Returns a set of all late-bound regions that are constrained
390 /// by `value`, meaning that if we instantiate those LBR with
391 /// variables and equate `value` with something else, those
392 /// variables will also be equated.
393 pub fn collect_constrained_late_bound_regions<T>(&self, value: &Binder<T>)
394 -> FnvHashSet<ty::BoundRegion>
395 where T : TypeFoldable<'tcx>
396 {
397 self.collect_late_bound_regions(value, true)
398 }
399
400 /// Returns a set of all late-bound regions that appear in `value` anywhere.
401 pub fn collect_referenced_late_bound_regions<T>(&self, value: &Binder<T>)
402 -> FnvHashSet<ty::BoundRegion>
403 where T : TypeFoldable<'tcx>
404 {
405 self.collect_late_bound_regions(value, false)
406 }
407
408 fn collect_late_bound_regions<T>(&self, value: &Binder<T>, just_constraint: bool)
409 -> FnvHashSet<ty::BoundRegion>
410 where T : TypeFoldable<'tcx>
411 {
412 let mut collector = LateBoundRegionsCollector::new(just_constraint);
413 let result = value.skip_binder().visit_with(&mut collector);
414 assert!(!result); // should never have stopped early
415 collector.regions
416 }
417
3157f602 418 /// Replace any late-bound regions bound in `value` with `'erased`. Useful in trans but also
e9174d1e 419 /// method lookup and a few other places where precise region relationships are not required.
a7813a04 420 pub fn erase_late_bound_regions<T>(self, value: &Binder<T>) -> T
e9174d1e
SL
421 where T : TypeFoldable<'tcx>
422 {
3157f602 423 self.replace_late_bound_regions(value, |_| ty::ReErased).0
e9174d1e
SL
424 }
425
426 /// Rewrite any late-bound regions so that they are anonymous. Region numbers are
427 /// assigned starting at 1 and increasing monotonically in the order traversed
428 /// by the fold operation.
429 ///
430 /// The chief purpose of this function is to canonicalize regions so that two
431 /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become
432 /// structurally identical. For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and
433 /// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization.
a7813a04 434 pub fn anonymize_late_bound_regions<T>(self, sig: &Binder<T>) -> Binder<T>
e9174d1e
SL
435 where T : TypeFoldable<'tcx>,
436 {
437 let mut counter = 0;
438 Binder(self.replace_late_bound_regions(sig, |_| {
439 counter += 1;
440 ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(counter))
441 }).0)
442 }
443}
444
a7813a04
XL
445impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> {
446 fn new<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, fld_r: &'a mut F)
447 -> RegionReplacer<'a, 'gcx, 'tcx>
e9174d1e
SL
448 where F : FnMut(ty::BoundRegion) -> ty::Region
449 {
450 RegionReplacer {
451 tcx: tcx,
452 current_depth: 1,
453 fld_r: fld_r,
454 map: FnvHashMap()
455 }
456 }
457}
458
a7813a04
XL
459impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> {
460 fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
e9174d1e 461
54a0048b 462 fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
e9174d1e 463 self.current_depth += 1;
54a0048b 464 let t = t.super_fold_with(self);
e9174d1e 465 self.current_depth -= 1;
54a0048b 466 t
e9174d1e
SL
467 }
468
469 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
470 if !t.has_regions_escaping_depth(self.current_depth-1) {
471 return t;
472 }
473
9cc50fc6 474 t.super_fold_with(self)
e9174d1e
SL
475 }
476
477 fn fold_region(&mut self, r: ty::Region) -> ty::Region {
478 match r {
479 ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {
e9174d1e
SL
480 let fld_r = &mut self.fld_r;
481 let region = *self.map.entry(br).or_insert_with(|| fld_r(br));
482 if let ty::ReLateBound(debruijn1, br) = region {
483 // If the callback returns a late-bound region,
484 // that region should always use depth 1. Then we
485 // adjust it to the correct depth.
486 assert_eq!(debruijn1.depth, 1);
487 ty::ReLateBound(debruijn, br)
488 } else {
489 region
490 }
491 }
492 r => r
493 }
494 }
495}
496
497///////////////////////////////////////////////////////////////////////////
498// Region eraser
499
a7813a04 500impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
e9174d1e
SL
501 /// Returns an equivalent value with all free regions removed (note
502 /// that late-bound regions remain, because they are important for
503 /// subtyping, but they are anonymized and normalized as well)..
a7813a04 504 pub fn erase_regions<T>(self, value: &T) -> T
e9174d1e
SL
505 where T : TypeFoldable<'tcx>
506 {
507 let value1 = value.fold_with(&mut RegionEraser(self));
508 debug!("erase_regions({:?}) = {:?}",
509 value, value1);
510 return value1;
511
a7813a04 512 struct RegionEraser<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(TyCtxt<'a, 'gcx, 'tcx>);
e9174d1e 513
a7813a04
XL
514 impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionEraser<'a, 'gcx, 'tcx> {
515 fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.0 }
e9174d1e
SL
516
517 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
3157f602
XL
518 if let Some(u) = self.tcx().normalized_cache.borrow().get(&ty).cloned() {
519 return u;
e9174d1e
SL
520 }
521
a7813a04
XL
522 // FIXME(eddyb) should local contexts have a cache too?
523 if let Some(ty_lifted) = self.tcx().lift_to_global(&ty) {
524 let tcx = self.tcx().global_tcx();
525 let t_norm = ty_lifted.super_fold_with(&mut RegionEraser(tcx));
526 tcx.normalized_cache.borrow_mut().insert(ty_lifted, t_norm);
527 t_norm
528 } else {
529 ty.super_fold_with(self)
530 }
e9174d1e
SL
531 }
532
533 fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
534 where T : TypeFoldable<'tcx>
535 {
536 let u = self.tcx().anonymize_late_bound_regions(t);
9cc50fc6 537 u.super_fold_with(self)
e9174d1e
SL
538 }
539
540 fn fold_region(&mut self, r: ty::Region) -> ty::Region {
541 // because late-bound regions affect subtyping, we can't
542 // erase the bound/free distinction, but we can replace
3157f602 543 // all free regions with 'erased.
e9174d1e
SL
544 //
545 // Note that we *CAN* replace early-bound regions -- the
546 // type system never "sees" those, they get substituted
3157f602 547 // away. In trans, they will always be erased to 'erased
e9174d1e
SL
548 // whenever a substitution occurs.
549 match r {
550 ty::ReLateBound(..) => r,
3157f602 551 _ => ty::ReErased
e9174d1e
SL
552 }
553 }
e9174d1e
SL
554 }
555 }
556}
557
558///////////////////////////////////////////////////////////////////////////
559// Region shifter
560//
561// Shifts the De Bruijn indices on all escaping bound regions by a
562// fixed amount. Useful in substitution or when otherwise introducing
563// a binding level that is not intended to capture the existing bound
564// regions. See comment on `shift_regions_through_binders` method in
565// `subst.rs` for more details.
566
567pub fn shift_region(region: ty::Region, amount: u32) -> ty::Region {
568 match region {
569 ty::ReLateBound(debruijn, br) => {
570 ty::ReLateBound(debruijn.shifted(amount), br)
571 }
572 _ => {
573 region
574 }
575 }
576}
577
a7813a04
XL
578pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
579 amount: u32, value: &T) -> T
580 where T: TypeFoldable<'tcx>
581{
e9174d1e
SL
582 debug!("shift_regions(value={:?}, amount={})",
583 value, amount);
584
585 value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| {
586 shift_region(region, amount)
587 }))
588}
9cc50fc6
SL
589
590/// An "escaping region" is a bound region whose binder is not part of `t`.
591///
592/// So, for example, consider a type like the following, which has two binders:
593///
594/// for<'a> fn(x: for<'b> fn(&'a isize, &'b isize))
595/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope
596/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ inner scope
597///
598/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the
599/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner
600/// fn type*, that type has an escaping region: `'a`.
601///
602/// Note that what I'm calling an "escaping region" is often just called a "free region". However,
603/// we already use the term "free region". It refers to the regions that we use to represent bound
604/// regions on a fn definition while we are typechecking its body.
605///
606/// To clarify, conceptually there is no particular difference between an "escaping" region and a
607/// "free" region. However, there is a big difference in practice. Basically, when "entering" a
608/// binding level, one is generally required to do some sort of processing to a bound region, such
609/// as replacing it with a fresh/skolemized region, or making an entry in the environment to
610/// represent the scope to which it is attached, etc. An escaping region represents a bound region
611/// for which this processing has not yet been done.
612struct HasEscapingRegionsVisitor {
613 depth: u32,
614}
615
616impl<'tcx> TypeVisitor<'tcx> for HasEscapingRegionsVisitor {
54a0048b 617 fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool {
9cc50fc6 618 self.depth += 1;
54a0048b 619 let result = t.super_visit_with(self);
9cc50fc6 620 self.depth -= 1;
54a0048b 621 result
9cc50fc6
SL
622 }
623
624 fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
625 t.region_depth > self.depth
626 }
627
628 fn visit_region(&mut self, r: ty::Region) -> bool {
629 r.escapes_depth(self.depth)
630 }
631}
632
633struct HasTypeFlagsVisitor {
634 flags: ty::TypeFlags,
635}
636
637impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
638 fn visit_ty(&mut self, t: Ty) -> bool {
639 t.flags.get().intersects(self.flags)
640 }
641
642 fn visit_region(&mut self, r: ty::Region) -> bool {
643 if self.flags.intersects(ty::TypeFlags::HAS_LOCAL_NAMES) {
644 // does this represent a region that cannot be named
645 // in a global way? used in fulfillment caching.
646 match r {
3157f602 647 ty::ReStatic | ty::ReEmpty | ty::ReErased => {}
9cc50fc6
SL
648 _ => return true,
649 }
650 }
651 if self.flags.intersects(ty::TypeFlags::HAS_RE_INFER) {
652 match r {
653 ty::ReVar(_) | ty::ReSkolemized(..) => { return true }
654 _ => {}
655 }
656 }
657 false
658 }
659}
a7813a04
XL
660
661/// Collects all the late-bound regions it finds into a hash set.
662struct LateBoundRegionsCollector {
663 current_depth: u32,
664 regions: FnvHashSet<ty::BoundRegion>,
665 just_constrained: bool,
666}
667
668impl LateBoundRegionsCollector {
669 fn new(just_constrained: bool) -> Self {
670 LateBoundRegionsCollector {
671 current_depth: 1,
672 regions: FnvHashSet(),
673 just_constrained: just_constrained,
674 }
675 }
676}
677
678impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
679 fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool {
680 self.current_depth += 1;
681 let result = t.super_visit_with(self);
682 self.current_depth -= 1;
683 result
684 }
685
686 fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
687 // if we are only looking for "constrained" region, we have to
688 // ignore the inputs to a projection, as they may not appear
689 // in the normalized form
690 if self.just_constrained {
691 match t.sty {
5bcae85e 692 ty::TyProjection(..) | ty::TyAnon(..) => { return false; }
a7813a04
XL
693 _ => { }
694 }
695 }
696
697 t.super_visit_with(self)
698 }
699
700 fn visit_region(&mut self, r: ty::Region) -> bool {
701 match r {
702 ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {
703 self.regions.insert(br);
704 }
705 _ => { }
706 }
707 false
708 }
709}