8000 Fixed a bug that led to a false positive error when calling a constru… · sourcegraph/scip-python@8f401e3 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8f401e3

Browse files
committed
Fixed a bug that led to a false positive error when calling a constructor using bidirectional type inference on a generic class that defines a __new__ method but no __init__ method. This addresses microsoft/pyright#4890.
1 parent ff134e6 commit 8f401e3

File tree

3 files changed

+59
-5
lines changed

3 files changed

+59
-5
lines changed

packages/pyright-internal/src/analyzer/typeEvaluator.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8625,7 +8625,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
86258625
initMethodType
86268626
);
86278627

8628-
if (expectedCallResult) {
8628+
if (expectedCallResult && !expectedCallResult.argumentErrors) {
86298629
returnType = expectedCallResult.returnType;
86308630

86318631
if (expectedCallResult.isTypeIncomplete) {
@@ -8725,6 +8725,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
87258725

87268726
if (constructorMethodInfo && !skipConstructorCheck(constructorMethodInfo.type)) {
87278727
const constructorMethodType = constructorMethodInfo.type;
8728+
let newReturnType: Type | undefined;
87288729

87298730
// If there is an expected type that was not applied above when
87308731
// handling the __init__ method, try to apply it with the __new__ method.
@@ -8738,8 +8739,9 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
87388739
constructorMethodType
87398740
);
87408741

8741-
if (expectedCallResult) {
8742-
returnType = expectedCallResult.returnType;
8742+
if (expectedCallResult && !expectedCallResult.argumentErrors) {
8743+
newReturnType = expectedCallResult.returnType;
8744+
returnType = newReturnType;
87438745

87448746
if (expectedCallResult.isTypeIncomplete) {
87458747
isTypeIncomplete = true;
@@ -8786,8 +8788,8 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
87868788

87878789
if (callResult.argumentErrors) {
87888790
reportedErrors = true;
8789-
} else {
8790-
let newReturnType = callResult.returnType;
8791+
} else if (!newReturnType) {
8792+
newReturnType = callResult.returnType;
87918793

87928794
// If the constructor returned an object whose type matches the class of
87938795
// the original type being constructed, use the return type in case it was
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# This sample tests the case where a constructor for a generic
2+
# class is called with an inference context (i.e. using bidirectional
3+
# type inference) and literals are used as type arguments.
4+
5+
from typing import Any, Generic, Literal, Self, TypeVar
6+
7+
_N = TypeVar("_N")
8+
_M = TypeVar("_M")
9+
10+
11+
class A(Generic[_M, _N]):
12+
def __new__(cls, m: _M, n: _N) -> "A[_M, _N]":
13+
...
14+
15+
16+
a: A[Literal[3], Literal[4]] = A(3, 4)
17+
18+
19+
class B(Generic[_M, _N]):
20+
def __new__(cls, m: _M, n: _N) -> A[_M, _N]:
21+
...
22+
23+
def __init__(self, *args: Any, **kwargs: Any) -> None:
24+
...
25+
26+
27+
b: B[Literal[3], Literal[4]] = B(3, 4)
28+
29+
30+
class C(Generic[_M, _N]):
31+
def __new__(cls, m: _M, n: _N) -> A[_M, _N]:
32+
...
33+
34+
def __init__(self, m: _M, n: _N) -> None:
35+
...
36+
37+
38+
c: C[Literal[3], Literal[4]] = C(3, 4)
39+
40+
41+
class D(Generic[_M, _N]):
42+
def __new__(cls, m: _M, n: _N) -> Self:
43+
...
44+
45+
46+
d: D[Literal[3], Literal[4]] = D(3, 4)

packages/pyright-internal/src/tests/typeEvaluator3.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,6 +1358,12 @@ test('Constructor14', () => {
13581358
TestUtils.validateResults(analysisResults, 0);
13591359
});
13601360

1361+
test('Constructor15', () => {
1362+
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['constructor15.py']);
1363+
1364+
TestUtils.validateResults(analysisResults, 0);
1365+
});
1366+
13611367
test('InconsistentConstructor1', () => {
13621368
const configOptions = new ConfigOptions('.');
13631369

0 commit comments

Comments
 (0)
0