Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changed type evaluation behavior for accesses to attributes on a clas… #6137

Merged
merged 1 commit into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading