mirror of
https://github.com/microsoft/pyright.git
synced 2024-10-03 19:37:39 +03:00
Fixed bug that incorrectly evaluates a constructor call to a constructor that infers a class-scoped ParamSpec when the passed function is generic. This addresses #8170. (#8215)
This commit is contained in:
parent
6ffb60bd53
commit
3a263135ab
@ -11640,6 +11640,11 @@ export function createTypeEvaluator(
|
||||
paramSpecTypeVarContext.forEach((paramSpecTypeVarContext) => {
|
||||
if (paramSpecTypeVarContext) {
|
||||
specializedReturnType = applySolvedTypeVars(specializedReturnType, paramSpecTypeVarContext);
|
||||
|
||||
// It's possible that one or more of the TypeVars or ParamSpecs
|
||||
// in the typeVarContext refer to TypeVars that were solved in
|
||||
// the paramSpecTypeVarContext. Apply these solved TypeVars accordingly.
|
||||
applySourceContextTypeVars(typeVarContext, paramSpecTypeVarContext);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -3329,7 +3329,7 @@ export function convertParamSpecValueToType(type: FunctionType): Type {
|
||||
FunctionType.addHigherOrderTypeVarScopeIds(functionType, withoutParamSpec.details.typeVarScopeId);
|
||||
FunctionType.addHigherOrderTypeVarScopeIds(functionType, withoutParamSpec.details.higherOrderTypeVarScopeIds);
|
||||
|
||||
withoutParamSpec.details.parameters.forEach((entry) => {
|
||||
withoutParamSpec.details.parameters.forEach((entry, index) => {
|
||||
FunctionType.addParameter(functionType, {
|
||||
category: entry.category,
|
||||
name: entry.name,
|
||||
@ -3337,7 +3337,7 @@ export function convertParamSpecValueToType(type: FunctionType): Type {
|
||||
defaultValueExpression: entry.defaultValueExpression,
|
||||
isNameSynthesized: entry.isNameSynthesized,
|
||||
hasDeclaredType: true,
|
||||
type: entry.type,
|
||||
type: FunctionType.getEffectiveParameterType(withoutParamSpec, index),
|
||||
});
|
||||
});
|
||||
|
||||
|
31
packages/pyright-internal/src/tests/samples/constructor30.py
Normal file
31
packages/pyright-internal/src/tests/samples/constructor30.py
Normal file
@ -0,0 +1,31 @@
|
||||
# This sample tests the case where a class is parameterized by a ParamSpec
|
||||
# which is inferred by a call to the constructor, and the passed value
|
||||
# is a generic function whose types are informed by additional parameters
|
||||
# also passed to the constructor.
|
||||
|
||||
from typing import Callable, Generic, ParamSpec, TypeVar
|
||||
|
||||
P = ParamSpec("P")
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class ABase: ...
|
||||
|
||||
|
||||
class A(ABase): ...
|
||||
|
||||
|
||||
TA = TypeVar("TA", bound=ABase)
|
||||
|
||||
|
||||
class B(Generic[P, T]):
|
||||
def __init__(
|
||||
self, _type: Callable[P, T], *args: P.args, **kwargs: P.kwargs
|
||||
) -> None: ...
|
||||
|
||||
|
||||
def func1(t: type[TA]) -> TA: ...
|
||||
|
||||
|
||||
b = B(func1, A)
|
||||
reveal_type(b, expected_text="B[(t: type[A]), A]")
|
@ -773,6 +773,12 @@ test('Constructor29', () => {
|
||||
TestUtils.validateResults(analysisResults, 0);
|
||||
});
|
||||
|
||||
test('Constructor30', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['constructor30.py']);
|
||||
|
||||
TestUtils.validateResults(analysisResults, 0);
|
||||
});
|
||||
|
||||
test('ConstructorCallable1', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['constructorCallable1.py']);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user