diff --git a/pyrefly/lib/solver/solver.rs b/pyrefly/lib/solver/solver.rs index bc080605d7..2a03d7c892 100644 --- a/pyrefly/lib/solver/solver.rs +++ b/pyrefly/lib/solver/solver.rs @@ -1434,6 +1434,19 @@ impl<'a, Ans: LookupAnswer> Subset<'a, Ans> { let name = q.name.clone(); let bound = q.restriction().as_type(self.type_order.stdlib()); drop(v1_ref); + drop(variables); + // When checking `$T <: t2` where `$T` has bound `B`: + // If `B <: t2`, then any value of `$T` (which is a subtype of `B`) + // is also a subtype of `t2`, so the constraint is satisfied. + // This handles cases like `$T: int` vs `Any | SomeType` where + // the bound `int` is a subtype of the target type. + // We set the variable to the bound to ensure it gets resolved. + if self.is_subset_eq(&bound, t2).is_ok() { + let variables = self.solver.variables.lock(); + variables.update(*v1, Variable::Answer(bound)); + return Ok(()); + } + let variables = self.solver.variables.lock(); variables.update(*v1, Variable::Answer(t2.clone())); drop(variables); if let Err(e) = self.is_subset_eq(t2, &bound) { diff --git a/pyrefly/lib/test/callable.rs b/pyrefly/lib/test/callable.rs index 34e32c396f..e06a4b85da 100644 --- a/pyrefly/lib/test/callable.rs +++ b/pyrefly/lib/test/callable.rs @@ -1164,3 +1164,32 @@ class A: assert_type(f(), int) "#, ); + +// Regression test for https://github.com/facebook/pyrefly/issues/1960 +// When a class with bounded type parameters is used as a constructor +// and the __init__ parameter type is a union involving the type parameter, +// the bound check should pass when the bound is assignable to the expected type. +testcase!( + test_callable_constructor_bounded_typevar_with_union_param, + r#" +from collections.abc import Callable + + +class Box[U]: + pass + + +class Result[T: int]: + def __init__(self, x: T | Box[T]) -> None: + pass + + +def f[T: int](factory: Callable[[T], Result[T]]) -> None: + pass + + +# This should not error - Result's constructor satisfies the Callable constraint +# because Result.__init__ takes (T | Box[T]) which is a supertype of T +f(factory=Result) +"#, +);