Skip to content

Commit 93c98d7

Browse files
authored
Fixed bug that causes a false negative when using unquoted types in a TypedDict functional class definition if the types are forward declared. This addresses #10612. (#10869)
1 parent 29bb1b0 commit 93c98d7

4 files changed

Lines changed: 18 additions & 2 deletions

File tree

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21696,7 +21696,7 @@ export function createTypeEvaluator(
2169621696
}
2169721697

2169821698
const fileInfo = AnalyzerNodeInfo.getFileInfo(node);
21699-
if (isAnnotationEvaluationPostponed(fileInfo) || options?.forwardRefs) {
21699+
if ((isAnnotationEvaluationPostponed(fileInfo) || options?.forwardRefs) && !options?.runtimeTypeExpression) {
2170021700
flags |= EvalFlags.ForwardRefs;
2170121701
} else if (options?.parsesStringLiteral) {
2170221702
flags |= EvalFlags.ParsesStringLiteral;
@@ -22460,6 +22460,7 @@ export function createTypeEvaluator(
2246022460
allowFinal: true,
2246122461
allowRequired: true,
2246222462
allowReadOnly: true,
22463+
runtimeTypeExpression: true,
2246322464
}).type
2246422465
);
2246522466
} else {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ export interface ExpectedTypeOptions {
404404
typeFormArg?: boolean;
405405
forwardRefs?: boolean;
406406
typeExpression?: boolean;
407+
runtimeTypeExpression?: boolean;
407408
convertEllipsisToAny?: boolean;
408409
allowEllipsis?: boolean;
409410
}

packages/pyright-internal/src/tests/samples/typedDict6.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,17 @@ def foo(unknown_str_value: str):
8181
# This should generate an error because the name doesn't match.
8282
# the arguments are missing.
8383
Movie13 = TypedDict("NotMovie13", {"name": str, "year": int})
84+
85+
86+
# This should generate an error because CustomType1 is a forward reference
87+
# and is not quoted.
88+
Movie14 = TypedDict("Movie14", {"title": CustomType1, "year": "CustomType2"})
89+
90+
# This should generate an error because CustomType2 is a forward reference
91+
# and is not quoted.
92+
Movie15 = TypedDict("Movie15", title="CustomType1", year=CustomType2)
93+
94+
95+
class CustomType1: ...
96+
class CustomType2: ...
97+

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ test('TypedDict5', () => {
673673
test('TypedDict6', () => {
674674
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typedDict6.py']);
675675

676-
TestUtils.validateResults(analysisResults, 13);
676+
TestUtils.validateResults(analysisResults, 15);
677677
});
678678

679679
test('TypedDict7', () => {

0 commit comments

Comments
 (0)