Skip to content

Commit

Permalink
Changed type evaluation behavior for accesses to attributes on a clas…
Browse files Browse the repository at this point in the history
…s that derives from `Any`. Previously, these were evaluated as `Unknown`, but they are now evaluated as `Any`. This is related to #6136. (#6137)

Co-authored-by: Eric Traut <erictr@microsoft.com>
  • Loading branch information
erictraut and msfterictraut authored Oct 12, 2023
1 parent df62538 commit 2916bb2
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 8 deletions.
5 changes: 5 additions & 0 deletions packages/pyright-internal/src/analyzer/typeEvaluator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21519,6 +21519,11 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
isIncomplete: !!typeResult.isIncomplete,
};
}
} else if (isAnyOrUnknown(member.classType)) {
return {
type: member.classType,
isIncomplete: false,
};
}

return undefined;
Expand Down
4 changes: 2 additions & 2 deletions packages/pyright-internal/src/analyzer/typeEvaluatorTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ export interface TypeResult<T extends Type = Type> {

// Used for getTypeOfObjectMember to indicate that class
// that declares the member.
classType?: ClassType | UnknownType;
classType?: ClassType | UnknownType | AnyType;

// Variadic type arguments allow the shorthand "()" to
// represent an empty tuple (i.e. Tuple[()]).
Expand Down Expand Up @@ -390,7 +390,7 @@ export interface ClassMemberLookup {
isClassMember: boolean;

// The class that declares the accessed member.
classType?: ClassType | UnknownType;
classType?: ClassType | UnknownType | AnyType;

// True if the member is explicitly declared as ClassVar
// within a Protocol.
Expand Down
12 changes: 6 additions & 6 deletions packages/pyright-internal/src/analyzer/typeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export interface ClassMember {
symbol: Symbol;

// Partially-specialized class that contains the class member
classType: ClassType | UnknownType;
classType: ClassType | UnknownType | AnyType;

// True if it is an instance or class member; it can be both a class and
// an instance member in cases where a class variable is overridden
Expand Down Expand Up @@ -1483,11 +1483,11 @@ export function* getClassMemberIterator(
// The class derives from an unknown type, so all bets are off
// when trying to find a member. Return an unknown symbol.
const cm: ClassMember = {
symbol: Symbol.createWithType(SymbolFlags.None, UnknownType.create()),
symbol: Symbol.createWithType(SymbolFlags.None, mroClass),
isInstanceMember: false,
isClassMember: true,
isClassVar: false,
classType: UnknownType.create(),
classType: isAnyOrUnknown(mroClass) ? mroClass : UnknownType.create(),
isTypeDeclared: false,
skippedUndeclaredType: false,
};
Expand Down Expand Up @@ -1566,13 +1566,13 @@ export function* getClassMemberIterator(
}
} else if (isAnyOrUnknown(classType)) {
// The class derives from an unknown type, so all bets are off
// when trying to find a member. Return an unknown symbol.
// when trying to find a member. Return an Any or Unknown symbol.
const cm: ClassMember = {
symbol: Symbol.createWithType(SymbolFlags.None, UnknownType.create()),
symbol: Symbol.createWithType(SymbolFlags.None, classType),
isInstanceMember: false,
isClassMember: true,
isClassVar: false,
classType: UnknownType.create(),
classType,
isTypeDeclared: false,
skippedUndeclaredType: false,
};
Expand Down
20 changes: 20 additions & 0 deletions packages/pyright-internal/src/tests/samples/memberAccess24.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# This sample tests the case where an attribute is accessed from a
# class that derives from an unknown type or Any.

from typing import Any
from dummy import UnknownX # type: ignore


class DerivesFromUnknown(UnknownX):
pass


class DerivesFromAny(Any):
pass


v1 = DerivesFromUnknown().x
reveal_type(v1, expected_text="Unknown")

v2 = DerivesFromAny().x
reveal_type(v2, expected_text="Any")
5 changes: 5 additions & 0 deletions packages/pyright-internal/src/tests/typeEvaluator4.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,11 @@ test('MemberAccess23', () => {
TestUtils.validateResults(analysisResults, 0);
});

test('MemberAccess24', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['memberAccess24.py']);
TestUtils.validateResults(analysisResults, 0);
});

test('DataClassNamedTuple1', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['dataclassNamedTuple1.py']);

Expand Down

0 comments on commit 2916bb2

Please sign in to comment.