Auto merge of #45473 - SimonSapin:variance-red-green, r=nikomatsakis
Remove dependency tracking for variance computation This custom tracking is now replaced by the red/green algorithm. Fix https://github.com/rust-lang/rust/issues/45471
This commit is contained in:
commit
b2478052f8
6 changed files with 11 additions and 50 deletions
|
@ -755,13 +755,11 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::CrateVariancesMap {
|
||||||
hcx: &mut StableHashingContext<'gcx>,
|
hcx: &mut StableHashingContext<'gcx>,
|
||||||
hasher: &mut StableHasher<W>) {
|
hasher: &mut StableHasher<W>) {
|
||||||
let ty::CrateVariancesMap {
|
let ty::CrateVariancesMap {
|
||||||
ref dependencies,
|
|
||||||
ref variances,
|
ref variances,
|
||||||
// This is just an irrelevant helper value.
|
// This is just an irrelevant helper value.
|
||||||
empty_variance: _,
|
empty_variance: _,
|
||||||
} = *self;
|
} = *self;
|
||||||
|
|
||||||
dependencies.hash_stable(hcx, hasher);
|
|
||||||
variances.hash_stable(hcx, hasher);
|
variances.hash_stable(hcx, hasher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,6 @@ use rustc_const_math::ConstInt;
|
||||||
use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
|
use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
|
||||||
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
|
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
|
||||||
HashStable};
|
HashStable};
|
||||||
use rustc_data_structures::transitive_relation::TransitiveRelation;
|
|
||||||
|
|
||||||
use hir;
|
use hir;
|
||||||
|
|
||||||
|
@ -313,11 +312,6 @@ pub enum Variance {
|
||||||
/// `tcx.variances_of()` to get the variance for a *particular*
|
/// `tcx.variances_of()` to get the variance for a *particular*
|
||||||
/// item.
|
/// item.
|
||||||
pub struct CrateVariancesMap {
|
pub struct CrateVariancesMap {
|
||||||
/// This relation tracks the dependencies between the variance of
|
|
||||||
/// various items. In particular, if `a < b`, then the variance of
|
|
||||||
/// `a` depends on the sources of `b`.
|
|
||||||
pub dependencies: TransitiveRelation<DefId>,
|
|
||||||
|
|
||||||
/// For each item with generics, maps to a vector of the variance
|
/// For each item with generics, maps to a vector of the variance
|
||||||
/// of its generics. If an item has no generics, it will have no
|
/// of its generics. If an item has no generics, it will have no
|
||||||
/// entry.
|
/// entry.
|
||||||
|
|
|
@ -104,22 +104,16 @@ into two queries:
|
||||||
- `crate_variances` computes the variance for all items in the current crate.
|
- `crate_variances` computes the variance for all items in the current crate.
|
||||||
- `variances_of` accesses the variance for an individual reading; it
|
- `variances_of` accesses the variance for an individual reading; it
|
||||||
works by requesting `crate_variances` and extracting the relevant data.
|
works by requesting `crate_variances` and extracting the relevant data.
|
||||||
|
|
||||||
If you limit yourself to reading `variances_of`, your code will only
|
If you limit yourself to reading `variances_of`, your code will only
|
||||||
depend then on the inference inferred for that particular item.
|
depend then on the inference inferred for that particular item.
|
||||||
|
|
||||||
Eventually, the goal is to rely on the red-green dependency management
|
Ultimately, this setup relies on the red-green algorithm.
|
||||||
algorithm. At the moment, however, we rely instead on a hack, where
|
In particular, every variance query ultimately depends on -- effectively --
|
||||||
`variances_of` ignores the dependencies of accessing
|
all type definitions in the entire crate (through `crate_variances`),
|
||||||
`crate_variances` and instead computes the *correct* dependencies
|
but since most changes will not result in a change
|
||||||
itself. To this end, when we build up the constraints in the system,
|
to the actual results from variance inference,
|
||||||
we also built up a transitive `dependencies` relation as part of the
|
the `variances_of` query will wind up being considered green after it is re-evaluated.
|
||||||
crate map. A `(X, Y)` pair is added to the map each time we have a
|
|
||||||
constraint that the variance of some inferred for the item `X` depends
|
|
||||||
on the variance of some element of `Y`. This is to some extent a
|
|
||||||
mirroring of the inference graph in the dependency graph. This means
|
|
||||||
we can just completely ignore the fixed-point iteration, since it is
|
|
||||||
just shuffling values along this graph.
|
|
||||||
|
|
||||||
### Addendum: Variance on traits
|
### Addendum: Variance on traits
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@ use syntax::ast;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
||||||
|
|
||||||
use rustc_data_structures::transitive_relation::TransitiveRelation;
|
|
||||||
use rustc_data_structures::stable_hasher::StableHashingContextProvider;
|
use rustc_data_structures::stable_hasher::StableHashingContextProvider;
|
||||||
|
|
||||||
use super::terms::*;
|
use super::terms::*;
|
||||||
|
@ -38,11 +37,6 @@ pub struct ConstraintContext<'a, 'tcx: 'a> {
|
||||||
bivariant: VarianceTermPtr<'a>,
|
bivariant: VarianceTermPtr<'a>,
|
||||||
|
|
||||||
pub constraints: Vec<Constraint<'a>>,
|
pub constraints: Vec<Constraint<'a>>,
|
||||||
|
|
||||||
/// This relation tracks the dependencies between the variance of
|
|
||||||
/// various items. In particular, if `a < b`, then the variance of
|
|
||||||
/// `a` depends on the sources of `b`.
|
|
||||||
pub dependencies: TransitiveRelation<DefId>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Declares that the variable `decl_id` appears in a location with
|
/// Declares that the variable `decl_id` appears in a location with
|
||||||
|
@ -63,7 +57,6 @@ pub struct Constraint<'a> {
|
||||||
/// then while we are visiting `Bar<T>`, the `CurrentItem` would have
|
/// then while we are visiting `Bar<T>`, the `CurrentItem` would have
|
||||||
/// the def-id and the start of `Foo`'s inferreds.
|
/// the def-id and the start of `Foo`'s inferreds.
|
||||||
pub struct CurrentItem {
|
pub struct CurrentItem {
|
||||||
def_id: DefId,
|
|
||||||
inferred_start: InferredIndex,
|
inferred_start: InferredIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +74,6 @@ pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>)
|
||||||
invariant,
|
invariant,
|
||||||
bivariant,
|
bivariant,
|
||||||
constraints: Vec::new(),
|
constraints: Vec::new(),
|
||||||
dependencies: TransitiveRelation::new(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tcx.hir.krate().visit_all_item_likes(&mut constraint_cx);
|
tcx.hir.krate().visit_all_item_likes(&mut constraint_cx);
|
||||||
|
@ -201,7 +193,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
|
|
||||||
let id = tcx.hir.as_local_node_id(def_id).unwrap();
|
let id = tcx.hir.as_local_node_id(def_id).unwrap();
|
||||||
let inferred_start = self.terms_cx.inferred_starts[&id];
|
let inferred_start = self.terms_cx.inferred_starts[&id];
|
||||||
let current_item = &CurrentItem { def_id, inferred_start };
|
let current_item = &CurrentItem { inferred_start };
|
||||||
match tcx.type_of(def_id).sty {
|
match tcx.type_of(def_id).sty {
|
||||||
ty::TyAdt(def, _) => {
|
ty::TyAdt(def, _) => {
|
||||||
// Not entirely obvious: constraints on structs/enums do not
|
// Not entirely obvious: constraints on structs/enums do not
|
||||||
|
@ -410,12 +402,6 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a corresponding relation into the dependencies to
|
|
||||||
// indicate that the variance for `current` relies on `def_id`.
|
|
||||||
if self.tcx().dep_graph.is_fully_enabled() {
|
|
||||||
self.dependencies.add(current.def_id, def_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let (local, remote) = if let Some(id) = self.tcx().hir.as_local_node_id(def_id) {
|
let (local, remote) = if let Some(id) = self.tcx().hir.as_local_node_id(def_id) {
|
||||||
(Some(self.terms_cx.inferred_starts[&id]), None)
|
(Some(self.terms_cx.inferred_starts[&id]), None)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -94,20 +94,9 @@ fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId)
|
||||||
|
|
||||||
// Everything else must be inferred.
|
// Everything else must be inferred.
|
||||||
|
|
||||||
// Lacking red/green, we read the variances for all items here
|
let crate_map = tcx.crate_variances(LOCAL_CRATE);
|
||||||
// but ignore the dependencies, then re-synthesize the ones we need.
|
|
||||||
let crate_map = tcx.dep_graph.with_ignore(|| tcx.crate_variances(LOCAL_CRATE));
|
|
||||||
let dep_node = item_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
|
let dep_node = item_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
|
||||||
tcx.dep_graph.read(dep_node);
|
tcx.dep_graph.read(dep_node);
|
||||||
for &dep_def_id in crate_map.dependencies.less_than(&item_def_id) {
|
|
||||||
if dep_def_id.is_local() {
|
|
||||||
let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
|
|
||||||
tcx.dep_graph.read(dep_node);
|
|
||||||
} else {
|
|
||||||
let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVariances);
|
|
||||||
tcx.dep_graph.read(dep_node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
crate_map.variances.get(&item_def_id)
|
crate_map.variances.get(&item_def_id)
|
||||||
.unwrap_or(&crate_map.empty_variance)
|
.unwrap_or(&crate_map.empty_variance)
|
||||||
|
|
|
@ -34,7 +34,7 @@ struct SolveContext<'a, 'tcx: 'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn solve_constraints(constraints_cx: ConstraintContext) -> ty::CrateVariancesMap {
|
pub fn solve_constraints(constraints_cx: ConstraintContext) -> ty::CrateVariancesMap {
|
||||||
let ConstraintContext { terms_cx, dependencies, constraints, .. } = constraints_cx;
|
let ConstraintContext { terms_cx, constraints, .. } = constraints_cx;
|
||||||
|
|
||||||
let mut solutions = vec![ty::Bivariant; terms_cx.inferred_terms.len()];
|
let mut solutions = vec![ty::Bivariant; terms_cx.inferred_terms.len()];
|
||||||
for &(id, ref variances) in &terms_cx.lang_items {
|
for &(id, ref variances) in &terms_cx.lang_items {
|
||||||
|
@ -53,7 +53,7 @@ pub fn solve_constraints(constraints_cx: ConstraintContext) -> ty::CrateVariance
|
||||||
let variances = solutions_cx.create_map();
|
let variances = solutions_cx.create_map();
|
||||||
let empty_variance = Rc::new(Vec::new());
|
let empty_variance = Rc::new(Vec::new());
|
||||||
|
|
||||||
ty::CrateVariancesMap { dependencies, variances, empty_variance }
|
ty::CrateVariancesMap { variances, empty_variance }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> SolveContext<'a, 'tcx> {
|
impl<'a, 'tcx> SolveContext<'a, 'tcx> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue