Skip to content

Commit

Permalink
Fixed bug that affected the case where a class variable has a declare…
Browse files Browse the repository at this point in the history
…d type in a base class, and a subclass assigns a value to that class variable but doesn't (re)declare its type. In this case, the type of the expression assigned within the base class should use the expected type declared in the base class for type inference.
  • Loading branch information
msfterictraut committed Jan 21, 2021
1 parent 4b6b0cd commit c92c3ef
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 2 deletions.
24 changes: 24 additions & 0 deletions packages/pyright-internal/src/analyzer/typeEvaluator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1512,6 +1512,30 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
const symbolWithScope = lookUpSymbolRecursive(expression, expression.value, /* honorCodeFlow */ true);
if (symbolWithScope) {
symbol = symbolWithScope.symbol;

// Handle the case where the symbol is a class-level variable
// where the type isn't declared in this class but is in
// a parent class.
if (
getDeclaredTypeOfSymbol(symbol) === undefined &&
symbolWithScope.scope.type === ScopeType.Class
) {
const enclosingClass = ParseTreeUtils.getEnclosingClassOrFunction(expression);
if (enclosingClass && enclosingClass.nodeType === ParseNodeType.Class) {
const classTypeInfo = getTypeOfClass(enclosingClass);
if (classTypeInfo) {
const classMemberInfo = lookUpClassMember(
classTypeInfo.classType,
expression.value,
ClassMemberLookupFlags.SkipInstanceVariables |
ClassMemberLookupFlags.DeclaredTypesOnly
);
if (classMemberInfo) {
symbol = classMemberInfo.symbol;
}
}
}
}
}
break;
}
Expand Down
13 changes: 12 additions & 1 deletion packages/pyright-internal/src/tests/samples/classes5.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This sample tests the reportIncompatibleVariableOverride
# configuration option.

from typing import Union
from typing import List, Union


class ParentClass:
Expand All @@ -11,6 +11,8 @@ class ParentClass:
var4: int
var5: int
var6: int
var7: List[float]
var8: List[int]


class Subclass(ParentClass):
Expand All @@ -31,3 +33,12 @@ class Subclass(ParentClass):
@property
def var6(self) -> int:
return 3

# This should not generate an error because the inherited (expected)
# type of var7 is List[float], so the expression "[3, 4, 5]" should
# be inferred as List[float] rather than List[int].
var7 = [3, 4, 5]

# This should generate an error because floats are not allowed
# in a List[int].
var8 = [3.3, 45.6, 5.9]
2 changes: 1 addition & 1 deletion packages/pyright-internal/src/tests/typeEvaluator1.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1166,7 +1166,7 @@ test('Classes5', () => {
// Turn on errors.
configOptions.diagnosticRuleSet.reportIncompatibleVariableOverride = 'error';
analysisResults = TestUtils.typeAnalyzeSampleFiles(['classes5.py'], configOptions);
TestUtils.validateResults(analysisResults, 3);
TestUtils.validateResults(analysisResults, 4);
});

test('Classes6', () => {
Expand Down

0 comments on commit c92c3ef

Please sign in to comment.