Skip to content

Commit bf6e715

Browse files
authored
Rollup merge of #69967 - mark-i-m:rinfctx, r=matthewjasper
Remove a few `Rc`s from RegionInferenceCtxt fixes #55853 r? @matthewjasper
2 parents f40272c + a58b17f commit bf6e715

File tree

5 files changed

+77
-10
lines changed

5 files changed

+77
-10
lines changed
+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//! An immutable, owned value (except for interior mutability).
2+
//!
3+
//! The purpose of `Frozen` is to make a value immutable for the sake of defensive programming. For example,
4+
//! suppose we have the following:
5+
//!
6+
//! ```rust
7+
//! struct Bar { /* some data */ }
8+
//!
9+
//! struct Foo {
10+
//! /// Some computed data that should never change after construction.
11+
//! pub computed: Bar,
12+
//!
13+
//! /* some other fields */
14+
//! }
15+
//!
16+
//! impl Bar {
17+
//! /// Mutate the `Bar`.
18+
//! pub fn mutate(&mut self) { }
19+
//! }
20+
//! ```
21+
//!
22+
//! Now suppose we want to pass around a mutable `Foo` instance but, we want to make sure that
23+
//! `computed` does not change accidentally (e.g. somebody might accidentally call
24+
//! `foo.computed.mutate()`). This is what `Frozen` is for. We can do the following:
25+
//!
26+
//! ```rust
27+
//! use rustc_data_structures::frozen::Frozen;
28+
//!
29+
//! struct Foo {
30+
//! /// Some computed data that should never change after construction.
31+
//! pub computed: Frozen<Bar>,
32+
//!
33+
//! /* some other fields */
34+
//! }
35+
//! ```
36+
//!
37+
//! `Frozen` impls `Deref`, so we can ergonomically call methods on `Bar`, but it doesn't `impl
38+
//! DerefMut`. Now calling `foo.compute.mutate()` will result in a compile-time error stating that
39+
//! `mutate` requires a mutable reference but we don't have one.
40+
//!
41+
//! # Caveats
42+
//!
43+
//! - `Frozen` doesn't try to defend against interior mutability (e.g. `Frozen<RefCell<Bar>>`).
44+
//! - `Frozen` doesn't pin it's contents (e.g. one could still do `foo.computed =
45+
//! Frozen::freeze(new_bar)`).
46+
47+
/// An owned immutable value.
48+
#[derive(Debug)]
49+
pub struct Frozen<T>(T);
50+
51+
impl<T> Frozen<T> {
52+
pub fn freeze(val: T) -> Self {
53+
Frozen(val)
54+
}
55+
}
56+
57+
impl<T> std::ops::Deref for Frozen<T> {
58+
type Target = T;
59+
60+
fn deref(&self) -> &T {
61+
&self.0
62+
}
63+
}

src/librustc_data_structures/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ pub mod profiling;
9494
pub mod vec_linked_list;
9595
pub mod work_queue;
9696
pub use atomic_ref::AtomicRef;
97+
pub mod frozen;
9798

9899
pub struct OnDrop<F: Fn()>(pub F);
99100

src/librustc_mir/borrow_check/region_infer/mod.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc::mir::{
77
};
88
use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable};
99
use rustc_data_structures::binary_search_util;
10+
use rustc_data_structures::frozen::Frozen;
1011
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1112
use rustc_data_structures::graph::scc::Sccs;
1213
use rustc_hir::def_id::DefId;
@@ -54,12 +55,12 @@ pub struct RegionInferenceContext<'tcx> {
5455
liveness_constraints: LivenessValues<RegionVid>,
5556

5657
/// The outlives constraints computed by the type-check.
57-
constraints: Rc<OutlivesConstraintSet>,
58+
constraints: Frozen<OutlivesConstraintSet>,
5859

5960
/// The constraint-set, but in graph form, making it easy to traverse
6061
/// the constraints adjacent to a particular region. Used to construct
6162
/// the SCC (see `constraint_sccs`) and for error reporting.
62-
constraint_graph: Rc<NormalConstraintGraph>,
63+
constraint_graph: Frozen<NormalConstraintGraph>,
6364

6465
/// The SCC computed from `constraints` and the constraint
6566
/// graph. We have an edge from SCC A to SCC B if `A: B`. Used to
@@ -112,7 +113,7 @@ pub struct RegionInferenceContext<'tcx> {
112113

113114
/// Information about how the universally quantified regions in
114115
/// scope on this function relate to one another.
115-
universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
116+
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
116117
}
117118

118119
/// Each time that `apply_member_constraint` is successful, it appends
@@ -242,11 +243,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
242243
///
243244
/// The `outlives_constraints` and `type_tests` are an initial set
244245
/// of constraints produced by the MIR type check.
245-
pub(crate) fn new(
246+
pub(in crate::borrow_check) fn new(
246247
var_infos: VarInfos,
247248
universal_regions: Rc<UniversalRegions<'tcx>>,
248249
placeholder_indices: Rc<PlaceholderIndices>,
249-
universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
250+
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
250251
outlives_constraints: OutlivesConstraintSet,
251252
member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
252253
closure_bounds_mapping: FxHashMap<
@@ -263,8 +264,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
263264
.map(|info| RegionDefinition::new(info.universe, info.origin))
264265
.collect();
265266

266-
let constraints = Rc::new(outlives_constraints); // freeze constraints
267-
let constraint_graph = Rc::new(constraints.graph(definitions.len()));
267+
let constraints = Frozen::freeze(outlives_constraints);
268+
let constraint_graph = Frozen::freeze(constraints.graph(definitions.len()));
268269
let fr_static = universal_regions.fr_static;
269270
let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph, fr_static));
270271

src/librustc_mir/borrow_check/type_check/free_region_relations.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use rustc::mir::ConstraintCategory;
22
use rustc::traits::query::OutlivesBound;
33
use rustc::ty::free_region_map::FreeRegionRelations;
44
use rustc::ty::{self, RegionVid, Ty, TyCtxt};
5+
use rustc_data_structures::frozen::Frozen;
56
use rustc_data_structures::transitive_relation::TransitiveRelation;
67
use rustc_infer::infer::canonical::QueryRegionConstraints;
78
use rustc_infer::infer::outlives;
@@ -53,7 +54,7 @@ type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>;
5354
type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>;
5455

5556
crate struct CreateResult<'tcx> {
56-
crate universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
57+
pub(in crate::borrow_check) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
5758
crate region_bound_pairs: RegionBoundPairs<'tcx>,
5859
crate normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
5960
}
@@ -298,7 +299,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
298299
}
299300

300301
CreateResult {
301-
universal_region_relations: Rc::new(self.relations),
302+
universal_region_relations: Frozen::freeze(self.relations),
302303
region_bound_pairs: self.region_bound_pairs,
303304
normalized_inputs_and_output,
304305
}

src/librustc_mir/borrow_check/type_check/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc::ty::{
1818
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, RegionVid, ToPolyTraitRef, Ty,
1919
TyCtxt, UserType, UserTypeAnnotationIndex,
2020
};
21+
use rustc_data_structures::frozen::Frozen;
2122
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
2223
use rustc_errors::struct_span_err;
2324
use rustc_hir as hir;
@@ -830,7 +831,7 @@ struct BorrowCheckContext<'a, 'tcx> {
830831

831832
crate struct MirTypeckResults<'tcx> {
832833
crate constraints: MirTypeckRegionConstraints<'tcx>,
833-
crate universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
834+
pub(in crate::borrow_check) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
834835
crate opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
835836
}
836837

0 commit comments

Comments
 (0)