Fix #11483: Incorrect type inference from context manager __exit__ return type with Generic#11502
Fix #11483: Incorrect type inference from context manager __exit__ return type with Generic#11502rchiodo wants to merge 3 commits into
Conversation
…ypes isExceptionContextManager read the unspecialized declared __exit__/__aexit__ return type, so a generic context manager whose exit return type is a TypeVar (e.g. ContextManager[bool]) was treated as non-suppressing. Use FunctionType.getEffectiveReturnType so the solved type argument is used instead. Fixes microsoft#11483 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
|
Fix looks correct and is well-tested. A couple of minor repo-convention/test-placement notes below; none are blocking. |
|
This change appears to be based on an out-of-date tree. The current working tree already resolves #11483 in codeFlowEngine.ts using applySolvedTypeVars, and both the With7 test and a richer with7.py (with SplitContextManager multi-TypeVar coverage) already exist. Please re-baseline onto the current subrepo state, confirm With7 is already green, and drop the redundant changes. Note also that packages/pyright is an upstream-owned subrepo per AGENTS.md. |
|
This PR appears stale relative to the current subrepo: the working tree already fixes #11483 in codeFlowEngine.ts (via applySolvedTypeVars), already has a With7 test in checker.test.ts, and already has a richer with7.py (including a multi-TypeVar SplitContextManager case). As-is, this would revert the better fix, create a duplicate test, and delete regression coverage. Please re-baseline onto current main and confirm With7 is already green before re-submitting. |
|
This change appears to be based on a stale baseline. The current subrepo already fixes #11483 in |
# Conflicts: # packages/pyright-internal/src/analyzer/codeFlowEngine.ts # packages/pyright-internal/src/tests/samples/with7.py
|
@heejaechang you're right — thanks for catching this. I verified your claim against current
I re-baselined
The only remaining diff vs
|
|
Diff from mypy_primer, showing the effect of this PR on open source code: sympy (https://github.com/sympy/sympy)
+ .../projects/sympy/sympy/solvers/diophantine/diophantine.py:176:44 - error: Cannot access attribute "expand" for class "Basic"
+ Attribute "expand" is unknown (reportAttributeAccessIssue)
- .../projects/sympy/sympy/solvers/diophantine/tests/test_diophantine.py:380:15 - error: Operator "*" not supported for "None" (reportOptionalOperand)
- .../projects/sympy/sympy/solvers/diophantine/tests/test_diophantine.py:383:13 - error: No overloads for "__init__" match the provided arguments (reportCallIssue)
- .../projects/sympy/sympy/solvers/diophantine/tests/test_diophantine.py:383:18 - error: Argument of type "list[Iterator[Unknown]]" cannot be assigned to parameter "iterable" of type "Iterable[list[bytes]]" in function "__init__" (reportArgumentType)
- .../projects/sympy/sympy/solvers/diophantine/tests/test_diophantine.py:383:78 - error: "args" is not a known attribute of "None" (reportOptionalMemberAccess)
+ .../projects/sympy/sympy/solvers/ode/lie_group.py:619:61 - error: Operator "-" not supported for type "Unknown | Basic" (reportOperatorIssue)
+ .../projects/sympy/sympy/solvers/ode/nonhomogeneous.py:225:45 - error: Cannot access attribute "has" for class "tuple[Expr, int]"
+ Attribute "has" is unknown (reportAttributeAccessIssue)
- .../projects/sympy/sympy/solvers/ode/nonhomogeneous.py:223:22 - error: No overloads for "__new__" match the provided arguments (reportCallIssue)
- .../projects/sympy/sympy/solvers/ode/nonhomogeneous.py:223:25 - error: Argument of type "CRootOf | tuple[Expr, int]" cannot be assigned to parameter "arg" of type "Expr" in function "__new__"
- Type "CRootOf | tuple[Expr, int]" is not assignable to type "Expr"
- "tuple[Expr, int]" is not assignable to "Expr" (reportArgumentType)
- .../projects/sympy/sympy/solvers/ode/nonhomogeneous.py:238:40 - error: No overloads for "__new__" match the provided arguments (reportCallIssue)
- .../projects/sympy/sympy/solvers/ode/nonhomogeneous.py:238:50 - error: Argument of type "CRootOf | tuple[Expr, int]" cannot be assigned to parameter "arg" of type "Expr" in function "__new__"
- Type "CRootOf | tuple[Expr, int]" is not assignable to type "Expr"
- "tuple[Expr, int]" is not assignable to "Expr" (reportArgumentType)
- .../projects/sympy/sympy/solvers/ode/single.py:867:9 - error: Expression with type "tuple[ComplexInfinity | Unknown | Any, list[tuple[Unknown, Unknown]] | list[Unknown]] | tuple[ComplexInfinity | Unknown | Any, list[tuple[Unknown, Unknown]] | list[Unknown], list[tuple[Unknown, Unknown]] | list[Unknown]]" cannot be assigned to target tuple
- Type "tuple[ComplexInfinity | Unknown | Any, list[tuple[Unknown, Unknown]] | list[Unknown], list[tuple[Unknown, Unknown]] | list[Unknown]]" is incompatible with target tuple
- Tuple size mismatch; expected 2 but received 3 (reportAssignmentType)
+ .../projects/sympy/sympy/solvers/ode/single.py:2646:27 - error: Argument of type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr | Unknown | int" cannot be assigned to parameter "stop" of type "SupportsIndex" in function "__new__"
+ Type "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr | Unknown | int" is not assignable to type "SupportsIndex"
+ "Expr" is incompatible with protocol "SupportsIndex"
+ "__index__" is not present (reportArgumentType)
- .../projects/sympy/sympy/solvers/ode/single.py:2652:9 - error: Operator "+=" not supported for types "Unknown | Any | Zero | One | NegativeOne | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr" and "Basic | Any | Unknown"
+ .../projects/sympy/sympy/solvers/ode/single.py:2652:9 - error: Operator "+=" not supported for types "One | NegativeOne | Zero | Integer | NaN | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | Expr | Any | Unknown" and "Basic | Any | Unknown"
- .../projects/sympy/sympy/solvers/ode/systems.py:1214:26 - error: Argument of type "dict[str, str | Unknown | Expr | bool | Symbol]" cannot be assigned to parameter "m" of type "Iterable[tuple[str, str]]" in function "update"
+ .../projects/sympy/sympy/solvers/ode/systems.py:1214:26 - error: Argument of type "dict[str, str | Unknown | Pow | bool | Symbol]" cannot be assigned to parameter "m" of type "Iterable[tuple[str, str]]" in function "update"
- .../projects/sympy/sympy/stats/crv_types.py:2544:9 - error: Method "_cdf" overrides class "SingleContinuousDistribution" in an incompatible manner
- Return type mismatch: base method returns type "None", override returns type "ComplexInfinity | Unknown"
- Type "ComplexInfinity | Unknown" is not assignable to type "None"
- "ComplexInfinity" is not assignable to "None" (reportIncompatibleMethodOverride)
- .../projects/sympy/sympy/stats/crv_types.py:2723:9 - error: Method "_cdf" overrides class "SingleContinuousDistribution" in an incompatible manner
- Return type mismatch: base method returns type "None", override returns type "Expr | Unknown"
- Type "Expr | Unknown" is not assignable to type "None"
- "Expr" is not assignable to "None" (reportIncompatibleMethodOverride)
- .../projects/sympy/sympy/stats/drv.py:269:22 - error: Argument of type "Generator[tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic | int | None, None, None]" cannot be assigned to parameter "iterable" of type "Iterable[_SupportsSumNoDefaultT@sum]" in function "sum"
+ .../projects/sympy/sympy/stats/drv.py:269:22 - error: Argument of type "Generator[tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic | int | None, None, None]" cannot be assigned to parameter "iterable" of type "Iterable[_SupportsSumNoDefaultT@sum]" in function "sum"
- "Generator[tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic | int | None, None, None]" is not assignable to "Iterable[_SupportsSumNoDefaultT@sum]"
+ "Generator[tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic | int | None, None, None]" is not assignable to "Iterable[_SupportsSumNoDefaultT@sum]"
- Type parameter "_T_co@Iterable" is covariant, but "tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic | int | None" is not a subtype of "_SupportsSumNoDefaultT@sum"
+ Type parameter "_T_co@Iterable" is covariant, but "tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic | int | None" is not a subtype of "_SupportsSumNoDefaultT@sum"
- Type "tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic | int | None" is not assignable to type "_SupportsSumWithNoDefaultGiven"
+ Type "tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic | int | None" is not assignable to type "_SupportsSumWithNoDefaultGiven"
- Type "tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic | int | None" is not assignable to type "_SupportsSumWithNoDefaultGiven"
+ Type "tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic | int | None" is not assignable to type "_SupportsSumWithNoDefaultGiven"
- .../projects/sympy/sympy/stats/drv_types.py:293:16 - error: Operator "*" not supported for types "Expr" and "tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Zero | NaN | Piecewise | Basic"
+ .../projects/sympy/sympy/stats/drv_types.py:293:16 - error: Operator "*" not supported for types "Expr" and "tuple[Unknown, ...] | Unknown | Sum | Expr | ZeroMatrix | Add | Zero | NaN | Piecewise | Basic"
- .../projects/sympy/sympy/stats/random_matrix_models.py:111:36 - error: Operator "*" not supported for types "Expr" and "tuple[Unknown, ...] | Unknown | Product | Basic | BooleanFalse | BooleanTrue | Equality | Expr | NaN | One | Zero"
+ .../projects/sympy/sympy/stats/random_matrix_models.py:111:36 - error: Operator "*" not supported for types "Expr" and "tuple[Unknown, ...] | Unknown | Product | Basic | BooleanFalse | BooleanTrue | ComplexInfinity | Equality | Expr | Float | Infinity | Integer | NaN | NegativeInfinity | NegativeOne | Number | One | Rational | Zero"
- .../projects/sympy/sympy/stats/rv.py:473:25 - error: Argument of type "Expr | Lambda | Zero | One | Integral | Unknown | Probability | tuple[Unknown, ...] | Sum | ZeroMatrix | NaN | Piecewise | Basic | NegativeOne | Integer | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | int" cannot be assigned to parameter "args" of type "Expr | complex" in function "__new__"
+ .../projects/sympy/sympy/stats/rv.py:473:25 - error: Argument of type "Expr | Lambda | Zero | One | Integral | Unknown | Probability | tuple[Unknown, ...] | Sum | ZeroMatrix | Add | NaN | Piecewise | Basic | NegativeOne | Integer | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | int" cannot be assigned to parameter "args" of type "Expr | complex" in function "__new__"
- Type "Expr | Lambda | Zero | One | Integral | Unknown | Probability | tuple[Unknown, ...] | Sum | ZeroMatrix | NaN | Piecewise | Basic | NegativeOne | Integer | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | int" is not assignable to type "Expr | complex"
+ Type "Expr | Lambda | Zero | One | Integral | Unknown | Probability | tuple[Unknown, ...] | Sum | ZeroMatrix | Add | NaN | Piecewise | Basic | NegativeOne | Integer | ComplexInfinity | Rational | Infinity | NegativeInfinity | Float | Number | int" is not assignable to type "Expr | complex"
... (truncated 1304 lines) ...
|
Description
When a generic context manager annotates its
__exit__/__aexit__return type with aTypeVar(e.g.class ContextManager(Generic[T])where__exit__returnsTbound tobool | None), Pyright determined exception-suppression behavior from the unspecialized declared return type instead of the solved type argument. This made code-flow narrowing after thewithblock wrong —reveal_type(foo)wasLiteral[1]instead ofLiteral["str", 1]for abool-specialized manager.How you figured out what to do
Reproduced the issue with a generic context manager, then used the debugger to inspect
isExceptionContextManagerincodeFlowEngine.ts. At theboolcase:exitType.shared.declaredReturnType.shared.name="T"(the raw TypeVar — the bug)exitType.priv.specializedTypes.returnType.shared.name="bool"(the solved type)Because the declared type was the TypeVar
T, theClassType.isBuiltIn(returnType, 'bool')check never matched andcmSwallowsExceptionsstayedfalse.Implementation
In
isExceptionContextManager(codeFlowEngine.ts), useFunctionType.getEffectiveReturnType(exitType, /* includeInferred */ false)instead of readingshared.declaredReturnTypedirectly. The effective return type preferspriv.specializedTypes.returnType, so generic managers are evaluated using the solved type argument. The existing__aexit__Coroutine-unwrapping (third type arg) and literal-boolhandling are preserved.Testing
packages/pyright-internal/src/tests/samples/with7.pycovering generic sync and async context managers specialized toNoneandbool, asserting the narrowed type after the block viaassert_type.With7test case tochecker.test.ts.With7failed before the fix (4assert_typemismatches), passes after.checker.test(72) andtypeEvaluator1-8(1163) suites pass.tsc --noEmitclean.Addresses
Fixes #11483
Generated by fix_all_my_issues pipeline