Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit d66a337

Browse files
committed
Get rid of constrain and solve steps
1 parent 0e50c3c commit d66a337

File tree

2 files changed

+44
-95
lines changed

2 files changed

+44
-95
lines changed

src/tools/rust-analyzer/crates/hir-ty/src/generics.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,6 @@ impl Generics {
132132
self.params.len()
133133
}
134134

135-
pub(crate) fn len_self_lifetimes(&self) -> usize {
136-
self.params.len_lifetimes()
137-
}
138-
139-
pub(crate) fn has_trait_self(&self) -> bool {
140-
self.params.trait_self_param().is_some()
141-
}
142-
143135
/// (parent total, self param, type params, const params, impl trait list, lifetimes)
144136
pub(crate) fn provenance_split(&self) -> (usize, bool, usize, usize, usize, usize) {
145137
let mut self_param = false;

src/tools/rust-analyzer/crates/hir-ty/src/variance.rs

Lines changed: 44 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,9 @@ pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Option<Ar
3939
if count == 0 {
4040
return None;
4141
}
42-
let mut ctxt = Context {
43-
def,
44-
has_trait_self: generics.parent_generics().map_or(false, |it| it.has_trait_self()),
45-
len_self: generics.len_self(),
46-
len_self_lifetimes: generics.len_self_lifetimes(),
47-
generics,
48-
constraints: Vec::new(),
49-
db,
50-
};
42+
let variances = Context { generics, variances: vec![Variance::Bivariant; count], db }.solve();
5143

52-
ctxt.build_constraints_for_item();
53-
let res = ctxt.solve();
54-
res.is_empty().not().then(|| Arc::from_iter(res))
44+
variances.is_empty().not().then(|| Arc::from_iter(variances))
5545
}
5646

5747
pub(crate) fn variances_of_cycle(
@@ -172,25 +162,14 @@ struct InferredIndex(usize);
172162

173163
struct Context<'db> {
174164
db: &'db dyn HirDatabase,
175-
def: GenericDefId,
176-
has_trait_self: bool,
177-
len_self: usize,
178-
len_self_lifetimes: usize,
179165
generics: Generics,
180-
constraints: Vec<Constraint>,
181-
}
182-
183-
/// Declares that the variable `decl_id` appears in a location with
184-
/// variance `variance`.
185-
#[derive(Clone)]
186-
struct Constraint {
187-
inferred: InferredIndex,
188-
variance: Variance,
166+
variances: Vec<Variance>,
189167
}
190168

191169
impl Context<'_> {
192-
fn build_constraints_for_item(&mut self) {
193-
match self.def {
170+
fn solve(mut self) -> Vec<Variance> {
171+
tracing::debug!("solve(generics={:?})", self.generics);
172+
match self.generics.def() {
194173
GenericDefId::AdtId(adt) => {
195174
let db = self.db;
196175
let mut add_constraints_from_variant = |variant| {
@@ -225,6 +204,26 @@ impl Context<'_> {
225204
}
226205
_ => {}
227206
}
207+
let mut variances = self.variances;
208+
209+
// Const parameters are always invariant.
210+
// Make all const parameters invariant.
211+
for (idx, param) in self.generics.iter_id().enumerate() {
212+
if let GenericParamId::ConstParamId(_) = param {
213+
variances[idx] = Variance::Invariant;
214+
}
215+
}
216+
217+
// Functions are permitted to have unused generic parameters: make those invariant.
218+
if let GenericDefId::FunctionId(_) = self.generics.def() {
219+
for variance in &mut variances {
220+
if *variance == Variance::Bivariant {
221+
*variance = Variance::Invariant;
222+
}
223+
}
224+
}
225+
226+
variances
228227
}
229228

230229
fn contravariant(&mut self, variance: Variance) -> Variance {
@@ -353,14 +352,8 @@ impl Context<'_> {
353352
// Chalk has no params, so use placeholders for now?
354353
TyKind::Placeholder(index) => {
355354
let idx = crate::from_placeholder_idx(self.db, *index);
356-
let index = idx.local_id.into_raw().into_u32() as usize + self.len_self_lifetimes;
357-
let inferred = if idx.parent == self.def {
358-
InferredIndex(self.has_trait_self as usize + index)
359-
} else {
360-
InferredIndex(self.len_self + index)
361-
};
362-
tracing::debug!("add_constraint(index={:?}, variance={:?})", inferred, variance);
363-
self.constraints.push(Constraint { inferred, variance });
355+
let inferred = InferredIndex(self.generics.type_or_const_param_idx(idx).unwrap());
356+
self.constrain(inferred, variance);
364357
}
365358
TyKind::Function(f) => {
366359
self.add_constraints_from_sig(f, variance);
@@ -396,7 +389,7 @@ impl Context<'_> {
396389
if args.is_empty() {
397390
return;
398391
}
399-
if def_id == self.def {
392+
if def_id == self.generics.def() {
400393
// HACK: Workaround for the trivial cycle salsa case (see
401394
// recursive_one_bivariant_more_non_bivariant_params test)
402395
let variance_i = variance.xform(Variance::Bivariant);
@@ -463,18 +456,17 @@ impl Context<'_> {
463456
/// Adds constraints appropriate for a region appearing in a
464457
/// context with ambient variance `variance`
465458
fn add_constraints_from_region(&mut self, region: &Lifetime, variance: Variance) {
459+
tracing::debug!(
460+
"add_constraints_from_region(region={:?}, variance={:?})",
461+
region,
462+
variance
463+
);
466464
match region.data(Interner) {
467465
// FIXME: chalk has no params?
468466
LifetimeData::Placeholder(index) => {
469467
let idx = crate::lt_from_placeholder_idx(self.db, *index);
470-
let index = idx.local_id.into_raw().into_u32() as usize;
471-
let inferred = if idx.parent == self.def {
472-
InferredIndex(index)
473-
} else {
474-
InferredIndex(self.has_trait_self as usize + self.len_self + index)
475-
};
476-
tracing::debug!("add_constraint(index={:?}, variance={:?})", inferred, variance);
477-
self.constraints.push(Constraint { inferred, variance: variance.clone() });
468+
let inferred = InferredIndex(self.generics.lifetime_idx(idx).unwrap());
469+
self.constrain(inferred, variance);
478470
}
479471
LifetimeData::Static => {}
480472

@@ -513,50 +505,15 @@ impl Context<'_> {
513505
}
514506
}
515507
}
516-
}
517-
518-
impl Context<'_> {
519-
fn solve(self) -> Vec<Variance> {
520-
let mut solutions = vec![Variance::Bivariant; self.generics.len()];
521-
// Propagate constraints until a fixed point is reached. Note
522-
// that the maximum number of iterations is 2C where C is the
523-
// number of constraints (each variable can change values at most
524-
// twice). Since number of constraints is linear in size of the
525-
// input, so is the inference process.
526-
let mut changed = true;
527-
while changed {
528-
changed = false;
529-
530-
for constraint in &self.constraints {
531-
let &Constraint { inferred, variance } = constraint;
532-
let InferredIndex(inferred) = inferred;
533-
let old_value = solutions[inferred];
534-
let new_value = variance.glb(old_value);
535-
if old_value != new_value {
536-
solutions[inferred] = new_value;
537-
changed = true;
538-
}
539-
}
540-
}
541508

542-
// Const parameters are always invariant.
543-
// Make all const parameters invariant.
544-
for (idx, param) in self.generics.iter_id().enumerate() {
545-
if let GenericParamId::ConstParamId(_) = param {
546-
solutions[idx] = Variance::Invariant;
547-
}
548-
}
549-
550-
// Functions are permitted to have unused generic parameters: make those invariant.
551-
if let GenericDefId::FunctionId(_) = self.def {
552-
for variance in &mut solutions {
553-
if *variance == Variance::Bivariant {
554-
*variance = Variance::Invariant;
555-
}
556-
}
557-
}
558-
559-
solutions
509+
fn constrain(&mut self, inferred: InferredIndex, variance: Variance) {
510+
tracing::debug!(
511+
"constrain(index={:?}, variance={:?}, to={:?})",
512+
inferred,
513+
self.variances[inferred.0],
514+
variance
515+
);
516+
self.variances[inferred.0] = self.variances[inferred.0].glb(variance);
560517
}
561518
}
562519

0 commit comments

Comments
 (0)