Skip to content

Commit

Permalink
Merge branch 'microsoft:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
DetachHead authored Feb 14, 2024
2 parents 9012d5a + 4b206e3 commit 08a71d5
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 17 deletions.
42 changes: 30 additions & 12 deletions packages/pyright-internal/src/analyzer/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4813,14 +4813,17 @@ export class Checker extends ParseTreeWalker {
// If the parent class is a named tuple, all instance variables
// (other than dundered ones) are implicitly final.
const decl = localSymbol.getDeclarations()[0];
this._evaluator.addDiagnostic(
DiagnosticRule.reportIncompatibleVariableOverride,
LocMessage.namedTupleEntryRedeclared().format({
name,
className: parentSymbol.classType.details.name,
}),
decl.node
);

if (decl.type === DeclarationType.Variable) {
this._evaluator.addDiagnostic(
DiagnosticRule.reportIncompatibleVariableOverride,
LocMessage.namedTupleEntryRedeclared().format({
name,
className: parentSymbol.classType.details.name,
}),
decl.node
);
}
}
}
});
Expand All @@ -4838,19 +4841,34 @@ export class Checker extends ParseTreeWalker {

// Is there a custom "__new__" and/or "__init__" method? If so, we'll
// verify that the signature of these calls is compatible with the values.
const newMemberTypeResult = getBoundNewMethod(
let newMemberTypeResult = getBoundNewMethod(
this._evaluator,
node.name,
classType,
MemberAccessFlags.SkipBaseClasses
MemberAccessFlags.SkipObjectBaseClass
);
const initMemberTypeResult = getBoundInitMethod(

// If this __new__ comes from a built-in class like Enum, we'll ignore it.
if (newMemberTypeResult?.classType) {
if (isClass(newMemberTypeResult.classType) && ClassType.isBuiltIn(newMemberTypeResult.classType)) {
newMemberTypeResult = undefined;
}
}

let initMemberTypeResult = getBoundInitMethod(
this._evaluator,
node.name,
ClassType.cloneAsInstance(classType),
MemberAccessFlags.SkipBaseClasses
MemberAccessFlags.SkipObjectBaseClass
);

// If this __init__ comes from a built-in class like Enum, we'll ignore it.
if (initMemberTypeResult?.classType) {
if (isClass(initMemberTypeResult.classType) && ClassType.isBuiltIn(initMemberTypeResult.classType)) {
initMemberTypeResult = undefined;
}
}

classType.details.fields.forEach((symbol, name) => {
// Enum members don't have type annotations.
if (symbol.getTypedDeclarations().length > 0) {
Expand Down
11 changes: 8 additions & 3 deletions packages/pyright-internal/src/analyzer/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -516,9 +516,14 @@ export function getTypeOfEnumMember(
// it may implement some magic that computes different values for
// the "_value_" attribute. If we see a customer __new__ or __init__,
// we'll assume the value type is what we computed above, or Any.
const newMember = lookUpClassMember(classType, '__new__', MemberAccessFlags.SkipBaseClasses);
const initMember = lookUpClassMember(classType, '__init__', MemberAccessFlags.SkipBaseClasses);
if (newMember || initMember) {
const newMember = lookUpClassMember(classType, '__new__', MemberAccessFlags.SkipObjectBaseClass);
const initMember = lookUpClassMember(classType, '__init__', MemberAccessFlags.SkipObjectBaseClass);

if (newMember && isClass(newMember.classType) && !ClassType.isBuiltIn(newMember.classType)) {
return { type: valueType ?? AnyType.create(), isIncomplete };
}

if (initMember && isClass(initMember.classType) && !ClassType.isBuiltIn(initMember.classType)) {
return { type: valueType ?? AnyType.create(), isIncomplete };
}

Expand Down
2 changes: 1 addition & 1 deletion packages/pyright-internal/src/analyzer/sourceFileInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export class SourceFileInfo {
this._writableData = this._preEditData;
this._preEditData = undefined;

// Some states have changed. Force some of info to be re-calcuated.
// Some states have changed. Force some of info to be re-calculated.
this.sourceFile.dropParseAndBindInfo();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ export class CompletionProvider {
const isDeclaredStaticMethod =
isFunction(declaredType) && FunctionType.isStaticMethod(declaredType);

// Special-case the "__init__subclass__" method because it's an implicit
// Special-case the "__init_subclass__" method because it's an implicit
// classmethod that the type evaluator flags as a real classmethod.
const isDeclaredClassMethod =
isFunction(declaredType) &&
Expand Down
14 changes: 14 additions & 0 deletions packages/pyright-internal/src/tests/samples/enum1.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# This sample tests the type checker's handling of Enum.

from enum import Enum, EnumMeta, IntEnum
from typing import Self


TestEnum1 = Enum("TestEnum1", " A B, , ,C , \t D\t")
Expand Down Expand Up @@ -226,3 +227,16 @@ class TestEnum16(Enum):

reveal_type(TestEnum16.D, expected_text="Literal[TestEnum16.C]")
reveal_type(TestEnum16.D.value, expected_text="Literal[3]")


class TestEnum17(IntEnum):
def __new__(cls, val: int, doc: str) -> Self:
obj = int.__new__(cls, val)
obj._value_ = val
obj.__doc__ = doc
return obj


class TestEnum18(TestEnum17):
A = (1, "A")
B = (2, "B")
6 changes: 6 additions & 0 deletions packages/pyright-internal/src/tests/samples/namedTuple10.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@ class Point(NamedTuple):
x: int
y: int

def f(self):
pass


class BadPointWithName(Point):
name: str

# This should generate an error.
x: int

def f(self):
pass

0 comments on commit 08a71d5

Please sign in to comment.