Skip to content

Commit 34beb96

Browse files
rchen152meta-codesync[bot]
authored andcommitted
Refactor match against Quantified in is_subset_eq_var to not write an answer until the end
Summary: For #105. When a non-Variable type is compared against a Variable::Quantified, pyrefly currently eagerly solves the quantified to the type. We want to delay solving in some cases. In preparation for that, refactor the code to first compute an answer for the variable, then write it at the very end. Previously, it eagerly wrote the answer as soon as it had one. This diff does not change any user-facing behavior. Reviewed By: migeed-z Differential Revision: D96333266 fbshipit-source-id: 0c24ca1d61bb42154f385e25f3c03054046dda55
1 parent 3ee9fd6 commit 34beb96

File tree

1 file changed

+34
-48
lines changed

1 file changed

+34
-48
lines changed

pyrefly/lib/solver/solver.rs

Lines changed: 34 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1956,42 +1956,26 @@ impl<'a, Ans: LookupAnswer> Subset<'a, Ans> {
19561956
let bound =
19571957
restriction.as_type(self.type_order.stdlib(), &self.solver.heap);
19581958
drop(v2_ref);
1959+
drop(variables);
19591960

19601961
// For constrained TypeVars, promote to the matching constraint type.
1961-
if let Restriction::Constraints(ref constraints) = restriction {
1962-
variables.update(*v2, Variable::Answer(t1_p.clone()));
1963-
drop(variables);
1962+
let answer = if let Restriction::Constraints(ref constraints) = restriction
1963+
{
19641964
// Try promoted type first, then fall back to original (for literal bounds).
19651965
if let Some(constraint) =
19661966
self.find_matching_constraint(&t1_p, constraints)
19671967
{
1968-
let constraint = constraint.clone();
1969-
self.solver
1970-
.variables
1971-
.lock()
1972-
.update(*v2, Variable::Answer(constraint));
1968+
constraint.clone()
19731969
} else if let Some(constraint) =
19741970
self.find_matching_constraint(t1, constraints)
19751971
{
1976-
let constraint = constraint.clone();
1977-
self.solver
1978-
.variables
1979-
.lock()
1980-
.update(*v2, Variable::Answer(constraint));
1972+
constraint.clone()
19811973
} else if let Err(err_p) = self.is_subset_eq(&t1_p, &bound) {
19821974
// No individual constraint matched, but the type may still
19831975
// be assignable to the constraint union (e.g. an abstract
19841976
// `AnyStr` satisfies `str | bytes`). Fall back to bound
19851977
// checking, mirroring the non-constraint code path.
1986-
self.solver
1987-
.variables
1988-
.lock()
1989-
.update(*v2, Variable::Answer(t1.clone()));
19901978
if self.is_subset_eq(t1, &bound).is_err() {
1991-
self.solver
1992-
.variables
1993-
.lock()
1994-
.update(*v2, Variable::Answer(t1_p.clone()));
19951979
self.solver.instantiation_errors.write().insert(
19961980
*v2,
19971981
TypeVarSpecializationError {
@@ -2001,36 +1985,38 @@ impl<'a, Ans: LookupAnswer> Subset<'a, Ans> {
20011985
error: err_p,
20021986
},
20031987
);
1988+
t1_p.clone()
1989+
} else {
1990+
t1.clone()
20041991
}
1992+
} else {
1993+
t1_p.clone()
20051994
}
2006-
} else {
2007-
variables.update(*v2, Variable::Answer(t1_p.clone()));
2008-
drop(variables);
2009-
if let Err(err_p) = self.is_subset_eq(&t1_p, &bound) {
2010-
// If the promoted type fails, try again with the original type, in case the bound itself is literal.
2011-
// This could be more optimized, but errors are rare, so this code path should not be hot.
2012-
self.solver
2013-
.variables
2014-
.lock()
2015-
.update(*v2, Variable::Answer(t1.clone()));
2016-
if self.is_subset_eq(t1, &bound).is_err() {
2017-
// If the original type is also an error, use the promoted type.
2018-
self.solver
2019-
.variables
2020-
.lock()
2021-
.update(*v2, Variable::Answer(t1_p.clone()));
2022-
self.solver.instantiation_errors.write().insert(
2023-
*v2,
2024-
TypeVarSpecializationError {
2025-
name,
2026-
got: t1_p.clone(),
2027-
want: bound,
2028-
error: err_p,
2029-
},
2030-
);
2031-
}
1995+
} else if let Err(err_p) = self.is_subset_eq(&t1_p, &bound) {
1996+
// If the promoted type fails, try again with the original type, in case the bound itself is literal.
1997+
// This could be more optimized, but errors are rare, so this code path should not be hot.
1998+
if self.is_subset_eq(t1, &bound).is_err() {
1999+
// If the original type is also an error, use the promoted type.
2000+
self.solver.instantiation_errors.write().insert(
2001+
*v2,
2002+
TypeVarSpecializationError {
2003+
name,
2004+
got: t1_p.clone(),
2005+
want: bound,
2006+
error: err_p,
2007+
},
2008+
);
2009+
t1_p.clone()
2010+
} else {
2011+
t1.clone()
20322012
}
2033-
}
2013+
} else {
2014+
t1_p.clone()
2015+
};
2016+
self.solver
2017+
.variables
2018+
.lock()
2019+
.update(*v2, Variable::Answer(answer));
20342020
// Widen None to None | Any for PartialQuantified, matching
20352021
// the PartialContained behavior (see comment there).
20362022
if is_partial {

0 commit comments

Comments
 (0)