Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove a few Rcs from RegionInferenceCtxt #69967

Merged
merged 4 commits into from
Mar 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions src/librustc_data_structures/frozen.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//! An immutable, owned value (except for interior mutability).
//!
//! The purpose of `Frozen` is to make a value immutable for the sake of defensive programming. For example,
//! suppose we have the following:
//!
//! ```rust
//! struct Bar { /* some data */ }
//!
//! struct Foo {
//! /// Some computed data that should never change after construction.
//! pub computed: Bar,
//!
//! /* some other fields */
//! }
//!
//! impl Bar {
//! /// Mutate the `Bar`.
//! pub fn mutate(&mut self) { }
//! }
//! ```
//!
//! Now suppose we want to pass around a mutable `Foo` instance but, we want to make sure that
//! `computed` does not change accidentally (e.g. somebody might accidentally call
//! `foo.computed.mutate()`). This is what `Frozen` is for. We can do the following:
//!
//! ```rust
//! use rustc_data_structures::frozen::Frozen;
//!
//! struct Foo {
//! /// Some computed data that should never change after construction.
//! pub computed: Frozen<Bar>,
//!
//! /* some other fields */
//! }
//! ```
//!
//! `Frozen` impls `Deref`, so we can ergonomically call methods on `Bar`, but it doesn't `impl
//! DerefMut`. Now calling `foo.compute.mutate()` will result in a compile-time error stating that
//! `mutate` requires a mutable reference but we don't have one.
//!
//! # Caveats
//!
//! - `Frozen` doesn't try to defend against interior mutability (e.g. `Frozen<RefCell<Bar>>`).
//! - `Frozen` doesn't pin it's contents (e.g. one could still do `foo.computed =
//! Frozen::freeze(new_bar)`).

/// An owned immutable value.
#[derive(Debug)]
pub struct Frozen<T>(T);

impl<T> Frozen<T> {
pub fn freeze(val: T) -> Self {
Frozen(val)
}
}

impl<T> std::ops::Deref for Frozen<T> {
type Target = T;

fn deref(&self) -> &T {
&self.0
}
}
1 change: 1 addition & 0 deletions src/librustc_data_structures/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ pub mod profiling;
pub mod vec_linked_list;
pub mod work_queue;
pub use atomic_ref::AtomicRef;
pub mod frozen;

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

Expand Down
15 changes: 8 additions & 7 deletions src/librustc_mir/borrow_check/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use rustc::mir::{
};
use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable};
use rustc_data_structures::binary_search_util;
use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::graph::scc::Sccs;
use rustc_hir::def_id::DefId;
Expand Down Expand Up @@ -54,12 +55,12 @@ pub struct RegionInferenceContext<'tcx> {
liveness_constraints: LivenessValues<RegionVid>,

/// The outlives constraints computed by the type-check.
constraints: Rc<OutlivesConstraintSet>,
constraints: Frozen<OutlivesConstraintSet>,

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

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

/// Information about how the universally quantified regions in
/// scope on this function relate to one another.
universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
}

/// Each time that `apply_member_constraint` is successful, it appends
Expand Down Expand Up @@ -242,11 +243,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
///
/// The `outlives_constraints` and `type_tests` are an initial set
/// of constraints produced by the MIR type check.
pub(crate) fn new(
pub(in crate::borrow_check) fn new(
var_infos: VarInfos,
universal_regions: Rc<UniversalRegions<'tcx>>,
placeholder_indices: Rc<PlaceholderIndices>,
universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
outlives_constraints: OutlivesConstraintSet,
member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
closure_bounds_mapping: FxHashMap<
Expand All @@ -263,8 +264,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.map(|info| RegionDefinition::new(info.universe, info.origin))
.collect();

let constraints = Rc::new(outlives_constraints); // freeze constraints
let constraint_graph = Rc::new(constraints.graph(definitions.len()));
let constraints = Frozen::freeze(outlives_constraints);
let constraint_graph = Frozen::freeze(constraints.graph(definitions.len()));
let fr_static = universal_regions.fr_static;
let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph, fr_static));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use rustc::mir::ConstraintCategory;
use rustc::ty::free_region_map::FreeRegionRelations;
use rustc::ty::{self, RegionVid, Ty, TyCtxt};
use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::transitive_relation::TransitiveRelation;
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::region_constraints::GenericKind;
Expand Down Expand Up @@ -52,7 +53,7 @@ type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>;
type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>;

crate struct CreateResult<'tcx> {
crate universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
pub(in crate::borrow_check) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
crate region_bound_pairs: RegionBoundPairs<'tcx>,
crate normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
}
Expand Down Expand Up @@ -297,7 +298,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
}

CreateResult {
universal_region_relations: Rc::new(self.relations),
universal_region_relations: Frozen::freeze(self.relations),
region_bound_pairs: self.region_bound_pairs,
normalized_inputs_and_output,
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_mir/borrow_check/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use rustc::ty::{
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, RegionVid, ToPolyTraitRef, Ty,
TyCtxt, UserType, UserTypeAnnotationIndex,
};
use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::struct_span_err;
use rustc_hir as hir;
Expand Down Expand Up @@ -828,7 +829,7 @@ struct BorrowCheckContext<'a, 'tcx> {

crate struct MirTypeckResults<'tcx> {
crate constraints: MirTypeckRegionConstraints<'tcx>,
crate universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
pub(in crate::borrow_check) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
crate opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
}

Expand Down