|
| 1 | +// Copyright 2017 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 | +//! Code to extract the free regions declared on a function and the |
| 12 | +//! relationships between them. For example: |
| 13 | +//! |
| 14 | +//! ``` |
| 15 | +//! fn foo<'a, 'b, 'c: 'b>() { } |
| 16 | +//! ``` |
| 17 | +//! |
| 18 | +//! here we would be returning a map assigning each of `{'a, 'b, 'c}` |
| 19 | +//! to an index, as well as the `FreeRegionMap` which can compute |
| 20 | +//! relationships between them. |
| 21 | +//! |
| 22 | +//! The code in this file doesn't *do anything* with those results; it |
| 23 | +//! just returns them for other code to use. |
| 24 | +
|
| 25 | +use rustc::infer::InferCtxt; |
| 26 | +use rustc::middle::free_region::FreeRegionMap; |
| 27 | +use rustc::mir::transform::MirSource; |
| 28 | +use rustc::ty; |
| 29 | +use rustc::ty::subst::Substs; |
| 30 | +use rustc::util::nodemap::FxHashMap; |
| 31 | + |
| 32 | +#[derive(Debug)] |
| 33 | +pub struct FreeRegions<'tcx> { |
| 34 | + /// Given a free region defined on this function (either early- or |
| 35 | + /// late-bound), this maps it to its internal region index. The |
| 36 | + /// corresponding variable will be "capped" so that it cannot |
| 37 | + /// grow. |
| 38 | + pub indices: FxHashMap<ty::Region<'tcx>, usize>, |
| 39 | + |
| 40 | + /// The map from the typeck tables telling us how to relate free regions. |
| 41 | + pub free_region_map: &'tcx FreeRegionMap<'tcx>, |
| 42 | +} |
| 43 | + |
| 44 | +pub fn free_regions<'a, 'gcx, 'tcx>( |
| 45 | + infcx: &InferCtxt<'a, 'gcx, 'tcx>, |
| 46 | + source: MirSource, |
| 47 | +) -> FreeRegions<'tcx> { |
| 48 | + debug!("free_regions(source={:?})", source); |
| 49 | + |
| 50 | + let item_id = source.item_id(); |
| 51 | + let item_def_id = infcx.tcx.hir.local_def_id(item_id); |
| 52 | + |
| 53 | + let mut indices = FxHashMap(); |
| 54 | + |
| 55 | + // Extract the early regions. |
| 56 | + let item_substs = Substs::identity_for_item(infcx.tcx, item_def_id); |
| 57 | + for item_subst in item_substs { |
| 58 | + if let Some(region) = item_subst.as_region() { |
| 59 | + insert_free_region(&mut indices, region); |
| 60 | + } |
| 61 | + } |
| 62 | + |
| 63 | + // Extract the late-bound regions. Use the liberated fn sigs, |
| 64 | + // where the late-bound regions will have been converted into free |
| 65 | + // regions, and add them to the map. |
| 66 | + let fn_hir_id = infcx.tcx.hir.node_to_hir_id(item_id); |
| 67 | + let tables = infcx.tcx.typeck_tables_of(item_def_id); |
| 68 | + let fn_sig = tables.liberated_fn_sigs()[fn_hir_id].clone(); |
| 69 | + infcx |
| 70 | + .tcx |
| 71 | + .for_each_free_region(&fn_sig.inputs_and_output, |region| { |
| 72 | + if let ty::ReFree(_) = *region { |
| 73 | + insert_free_region(&mut indices, region); |
| 74 | + } |
| 75 | + }); |
| 76 | + |
| 77 | + debug!("free_regions: indices={:#?}", indices); |
| 78 | + |
| 79 | + FreeRegions { indices, free_region_map: &tables.free_region_map } |
| 80 | +} |
| 81 | + |
| 82 | +fn insert_free_region<'tcx>( |
| 83 | + free_regions: &mut FxHashMap<ty::Region<'tcx>, usize>, |
| 84 | + region: ty::Region<'tcx>, |
| 85 | +) { |
| 86 | + let len = free_regions.len(); |
| 87 | + free_regions.entry(region).or_insert(len); |
| 88 | +} |
0 commit comments