Skip to content

Commit 7e818af

Browse files
committed
Fixed bug that resulted in a false positive error when doing protocol matching where the object type (i.e. the self value) is a literal value. This addresses microsoft/pyright#4844.
1 parent 5cf4aed commit 7e818af

File tree

3 files changed

+33
-2
lines changed

3 files changed

+33
-2
lines changed

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@ function assignClassToProtocolInternal(
150150
const genericDestTypeVarContext = new TypeVarContext(getTypeVarScopeId(destType));
151151

152152
const selfTypeVarContext = new TypeVarContext(getTypeVarScopeId(destType));
153-
populateTypeVarContextForSelfType(selfTypeVarContext, destType, srcType);
153+
const noLiteralSrcType = evaluator.stripLiteralValue(srcType) as ClassType;
154+
populateTypeVarContextForSelfType(selfTypeVarContext, destType, noLiteralSrcType);
154155

155156
// If the source is a TypedDict, use the _TypedDict placeholder class
156157
// instead. We don't want to use the TypedDict members for protocol
@@ -248,7 +249,11 @@ function assignClassToProtocolInternal(
248249
evaluator.inferReturnTypeIfNecessary(symbolType);
249250
}
250251

251-
srcMemberType = partiallySpecializeType(symbolType, srcMemberInfo.classType, srcType);
252+
srcMemberType = partiallySpecializeType(
253+
symbolType,
254+
srcMemberInfo.classType,
255+
noLiteralSrcType
256+
);
252257
} else {
253258
srcMemberType = UnknownType.create();
254259
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# This sample tests the case where a protocol is specialized with
2+
# a literal type.
3+
4+
from typing import Literal, Protocol, Self
5+
6+
7+
class Negatable(Protocol):
8+
def __neg__(self) -> Self:
9+
...
10+
11+
12+
def func1(x: Negatable) -> None:
13+
...
14+
15+
16+
func1(0)
17+
18+
19+
def func2(val: Literal[0, 1]):
20+
func1(val)

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,6 +1263,12 @@ test('Protocol37', () => {
12631263
TestUtils.validateResults(analysisResults, 0);
12641264
});
12651265

1266+
test('Protocol38', () => {
1267+
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['protocol38.py']);
1268+
1269+
TestUtils.validateResults(analysisResults, 0);
1270+
});
1271+
12661272
test('TypedDict1', () => {
12671273
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typedDict1.py']);
12681274

0 commit comments

Comments
 (0)