Skip to content

Commit 8c83da9

Browse files
migeed-zmeta-codesync[bot]
authored andcommitted
Lift fixpoint out of compute_variance_env
Summary: Lift the nested `fixpoint` function out of `compute_variance_env` into a standalone method on `AnswersSolver`. There are no behavioral changes and we are preparing for reuse by a follow-up diff that adds protocol variance inference. Reviewed By: stroxler Differential Revision: D92892739 fbshipit-source-id: 1c2d71072f0df00ebcdd6f3c61fe5d5b7ad30e6a
1 parent 9da0562 commit 8c83da9

File tree

1 file changed

+51
-56
lines changed

1 file changed

+51
-56
lines changed

pyrefly/lib/alt/class/variance_inference.rs

Lines changed: 51 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -493,61 +493,6 @@ fn initialize_environment<'a>(
493493

494494
impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
495495
fn compute_variance_env(&self, class: &Class) -> VarianceEnv {
496-
fn fixpoint<'a, Ans: LookupAnswer>(
497-
solver: &AnswersSolver<'a, Ans>,
498-
mut env: VarianceEnv,
499-
) -> VarianceEnv {
500-
let mut changed = true;
501-
502-
while changed {
503-
changed = false;
504-
let mut new_environment: VarianceEnv = SmallMap::new();
505-
506-
for (my_class, params) in env.iter() {
507-
let mut new_params = params.clone();
508-
509-
let mut on_var =
510-
|name: &Name,
511-
variance: Variance,
512-
has_inferred: bool,
513-
_: PreInferenceVariance| {
514-
if let Some(old_status) = new_params.get_mut(name) {
515-
let new_inferred_variance =
516-
variance.union(old_status.inferred_variance);
517-
// Mark as inferred if:
518-
// 1. It was already marked as inferred, OR
519-
// 2. The caller says this is an injective (reliable) constraint, OR
520-
// 3. The inferred variance is no longer Bivariant (we found a constraint)
521-
// Case 3 fixes self-referential types where `has_inferred` is always false
522-
// but we still discover variance constraints through the fixpoint iteration.
523-
let new_has_variance_inferred = old_status.has_variance_inferred
524-
|| has_inferred
525-
|| new_inferred_variance != Variance::Bivariant;
526-
if new_inferred_variance != old_status.inferred_variance
527-
|| new_has_variance_inferred != old_status.has_variance_inferred
528-
{
529-
old_status.inferred_variance = new_inferred_variance;
530-
old_status.has_variance_inferred = new_has_variance_inferred;
531-
changed = true;
532-
}
533-
}
534-
};
535-
let mut on_edge = |c: &Class| env.get(c).cloned().unwrap_or_default();
536-
on_class(
537-
my_class,
538-
solver.heap,
539-
&mut on_edge,
540-
&mut on_var,
541-
&|c| solver.get_base_types_for_class(c),
542-
&|c| solver.get_class_field_map(c),
543-
);
544-
new_environment.insert(my_class.dupe(), new_params);
545-
}
546-
env = new_environment;
547-
}
548-
env
549-
}
550-
551496
let mut environment = VarianceEnv::new();
552497
let initial_inference_map_for_class =
553498
initial_inference_map(self.get_class_tparams(class).as_vec());
@@ -566,8 +511,58 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
566511
&|c| self.get_class_field_map(c),
567512
&|c| self.get_class_tparams(c),
568513
);
569-
fixpoint(self, environment)
514+
self.fixpoint(environment)
515+
}
516+
}
517+
518+
fn fixpoint(&self, mut env: VarianceEnv) -> VarianceEnv {
519+
let mut changed = true;
520+
521+
while changed {
522+
changed = false;
523+
let mut new_environment: VarianceEnv = SmallMap::new();
524+
525+
for (my_class, params) in env.iter() {
526+
let mut new_params = params.clone();
527+
528+
let mut on_var = |name: &Name,
529+
variance: Variance,
530+
has_inferred: bool,
531+
_: PreInferenceVariance| {
532+
if let Some(old_status) = new_params.get_mut(name) {
533+
let new_inferred_variance = variance.union(old_status.inferred_variance);
534+
// Mark as inferred if:
535+
// 1. It was already marked as inferred, OR
536+
// 2. The caller says this is an injective (reliable) constraint, OR
537+
// 3. The inferred variance is no longer Bivariant (we found a constraint)
538+
// Case 3 fixes self-referential types where `has_inferred` is always false
539+
// but we still discover variance constraints through the fixpoint iteration.
540+
let new_has_variance_inferred = old_status.has_variance_inferred
541+
|| has_inferred
542+
|| new_inferred_variance != Variance::Bivariant;
543+
if new_inferred_variance != old_status.inferred_variance
544+
|| new_has_variance_inferred != old_status.has_variance_inferred
545+
{
546+
old_status.inferred_variance = new_inferred_variance;
547+
old_status.has_variance_inferred = new_has_variance_inferred;
548+
changed = true;
549+
}
550+
}
551+
};
552+
let mut on_edge = |c: &Class| env.get(c).cloned().unwrap_or_default();
553+
on_class(
554+
my_class,
555+
self.heap,
556+
&mut on_edge,
557+
&mut on_var,
558+
&|c| self.get_base_types_for_class(c),
559+
&|c| self.get_class_field_map(c),
560+
);
561+
new_environment.insert(my_class.dupe(), new_params);
562+
}
563+
env = new_environment;
570564
}
565+
env
571566
}
572567

573568
/// Compute variance for a class, optionally checking for violations.

0 commit comments

Comments
 (0)