mirror of
https://github.com/microsoft/pyright.git
synced 2024-10-06 12:57:14 +03:00
Fixed bug that results in some circumstances in incorrect specialization of type[T]
when T
evaluates to Any
. This addresses #8429. (#8431)
This commit is contained in:
parent
6990c98c12
commit
042d2ea582
@ -5937,11 +5937,19 @@ export class Checker extends ParseTreeWalker {
|
||||
}
|
||||
|
||||
let overriddenType = this._evaluator.getEffectiveTypeOfSymbol(overriddenClassAndSymbol.symbol);
|
||||
overriddenType = partiallySpecializeType(overriddenType, overriddenClassAndSymbol.classType);
|
||||
overriddenType = partiallySpecializeType(
|
||||
overriddenType,
|
||||
overriddenClassAndSymbol.classType,
|
||||
this._evaluator.getTypeClassType()
|
||||
);
|
||||
|
||||
const overrideSymbol = overrideClassAndSymbol.symbol;
|
||||
let overrideType = this._evaluator.getEffectiveTypeOfSymbol(overrideSymbol);
|
||||
overrideType = partiallySpecializeType(overrideType, overrideClassAndSymbol.classType);
|
||||
overrideType = partiallySpecializeType(
|
||||
overrideType,
|
||||
overrideClassAndSymbol.classType,
|
||||
this._evaluator.getTypeClassType()
|
||||
);
|
||||
|
||||
const childOverrideSymbol = ClassType.getSymbolTable(childClassType).get(memberName);
|
||||
const childOverrideType = childOverrideSymbol
|
||||
@ -6174,7 +6182,11 @@ export class Checker extends ParseTreeWalker {
|
||||
|
||||
// Is the method present on the base class but missing in the subclass?
|
||||
if (baseClassPropMethod) {
|
||||
const baseClassMethodType = partiallySpecializeType(baseClassPropMethod, overriddenClassType);
|
||||
const baseClassMethodType = partiallySpecializeType(
|
||||
baseClassPropMethod,
|
||||
overriddenClassType,
|
||||
this._evaluator.getTypeClassType()
|
||||
);
|
||||
|
||||
if (isFunction(baseClassMethodType)) {
|
||||
if (!subclassPropMethod) {
|
||||
@ -6212,7 +6224,11 @@ export class Checker extends ParseTreeWalker {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const subclassMethodType = partiallySpecializeType(subclassPropMethod, overrideClassType);
|
||||
const subclassMethodType = partiallySpecializeType(
|
||||
subclassPropMethod,
|
||||
overrideClassType,
|
||||
this._evaluator.getTypeClassType()
|
||||
);
|
||||
|
||||
if (isFunction(subclassMethodType)) {
|
||||
if (
|
||||
@ -6634,10 +6650,16 @@ export class Checker extends ParseTreeWalker {
|
||||
const baseType = partiallySpecializeType(
|
||||
this._evaluator.getEffectiveTypeOfSymbol(baseClassAndSymbol.symbol),
|
||||
baseClass,
|
||||
this._evaluator.getTypeClassType(),
|
||||
childClassSelf
|
||||
);
|
||||
|
||||
overrideType = partiallySpecializeType(overrideType, childClassType, childClassSelf);
|
||||
overrideType = partiallySpecializeType(
|
||||
overrideType,
|
||||
childClassType,
|
||||
this._evaluator.getTypeClassType(),
|
||||
childClassSelf
|
||||
);
|
||||
|
||||
if (isFunction(baseType) || isOverloadedFunction(baseType)) {
|
||||
const diagAddendum = new DiagnosticAddendum();
|
||||
@ -6992,7 +7014,11 @@ export class Checker extends ParseTreeWalker {
|
||||
|
||||
// Is the method present on the base class but missing in the subclass?
|
||||
if (baseClassPropMethod) {
|
||||
const baseClassMethodType = partiallySpecializeType(baseClassPropMethod, baseClassType);
|
||||
const baseClassMethodType = partiallySpecializeType(
|
||||
baseClassPropMethod,
|
||||
baseClassType,
|
||||
this._evaluator.getTypeClassType()
|
||||
);
|
||||
|
||||
if (isFunction(baseClassMethodType)) {
|
||||
if (!subclassPropMethod) {
|
||||
@ -7022,7 +7048,11 @@ export class Checker extends ParseTreeWalker {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const subclassMethodType = partiallySpecializeType(subclassPropMethod, childClassType);
|
||||
const subclassMethodType = partiallySpecializeType(
|
||||
subclassPropMethod,
|
||||
childClassType,
|
||||
this._evaluator.getTypeClassType()
|
||||
);
|
||||
|
||||
if (isFunction(subclassMethodType)) {
|
||||
if (
|
||||
|
@ -244,7 +244,11 @@ export function getParameterListDetails(type: FunctionType): ParameterListDetail
|
||||
|
||||
const typedDictType = paramType;
|
||||
paramType.shared.typedDictEntries.knownItems.forEach((entry, name) => {
|
||||
const specializedParamType = partiallySpecializeType(entry.valueType, typedDictType);
|
||||
const specializedParamType = partiallySpecializeType(
|
||||
entry.valueType,
|
||||
typedDictType,
|
||||
/* typeClassType */ undefined
|
||||
);
|
||||
|
||||
addVirtualParameter(
|
||||
FunctionParam.create(
|
||||
|
@ -1250,7 +1250,11 @@ function getMappingPatternInfo(evaluator: TypeEvaluator, type: Type, node: Patte
|
||||
}
|
||||
|
||||
if (mroClassToSpecialize) {
|
||||
const specializedMapping = partiallySpecializeType(mroClassToSpecialize, concreteSubtype) as ClassType;
|
||||
const specializedMapping = partiallySpecializeType(
|
||||
mroClassToSpecialize,
|
||||
concreteSubtype,
|
||||
evaluator.getTypeClassType()
|
||||
) as ClassType;
|
||||
|
||||
if (specializedMapping.priv.typeArguments && specializedMapping.priv.typeArguments.length >= 2) {
|
||||
mappingInfo.push({
|
||||
@ -1346,7 +1350,11 @@ function getSequencePatternInfo(
|
||||
}
|
||||
|
||||
if (mroClassToSpecialize) {
|
||||
const specializedSequence = partiallySpecializeType(mroClassToSpecialize, concreteSubtype) as ClassType;
|
||||
const specializedSequence = partiallySpecializeType(
|
||||
mroClassToSpecialize,
|
||||
concreteSubtype,
|
||||
evaluator.getTypeClassType()
|
||||
) as ClassType;
|
||||
|
||||
if (isTupleClass(specializedSequence)) {
|
||||
const typeArgs = specializedSequence.priv.tupleTypeArguments ?? [
|
||||
|
@ -428,7 +428,12 @@ function assignClassToProtocolInternal(
|
||||
// We can skip this if it's the dest class because it is already
|
||||
// specialized.
|
||||
if (!ClassType.isSameGenericClass(mroClass, destType)) {
|
||||
destMemberType = partiallySpecializeType(destMemberType, mroClass, selfType);
|
||||
destMemberType = partiallySpecializeType(
|
||||
destMemberType,
|
||||
mroClass,
|
||||
evaluator.getTypeClassType(),
|
||||
selfType
|
||||
);
|
||||
}
|
||||
|
||||
if (isInstantiableClass(srcMemberInfo.classType)) {
|
||||
@ -439,7 +444,12 @@ function assignClassToProtocolInternal(
|
||||
evaluator.inferReturnTypeIfNecessary(symbolType);
|
||||
}
|
||||
|
||||
srcMemberType = partiallySpecializeType(symbolType, srcMemberInfo.classType, selfType);
|
||||
srcMemberType = partiallySpecializeType(
|
||||
symbolType,
|
||||
srcMemberInfo.classType,
|
||||
evaluator.getTypeClassType(),
|
||||
selfType
|
||||
);
|
||||
} else {
|
||||
srcMemberType = UnknownType.create();
|
||||
}
|
||||
@ -574,7 +584,7 @@ function assignClassToProtocolInternal(
|
||||
let getterType = evaluator.getGetterTypeFromProperty(destMemberType, /* inferTypeIfNeeded */ true);
|
||||
|
||||
if (getterType) {
|
||||
getterType = partiallySpecializeType(getterType, mroClass);
|
||||
getterType = partiallySpecializeType(getterType, mroClass, evaluator.getTypeClassType());
|
||||
}
|
||||
|
||||
if (
|
||||
|
@ -2697,7 +2697,7 @@ export function createTypeEvaluator(
|
||||
|
||||
if (classOrObjectBase) {
|
||||
if (memberAccessClass && isInstantiableClass(memberAccessClass)) {
|
||||
declaredType = partiallySpecializeType(declaredType, memberAccessClass);
|
||||
declaredType = partiallySpecializeType(declaredType, memberAccessClass, getTypeClassType());
|
||||
}
|
||||
|
||||
if (isFunction(declaredType) || isOverloadedFunction(declaredType)) {
|
||||
@ -3017,6 +3017,13 @@ export function createTypeEvaluator(
|
||||
return unionTypeClass ?? UnknownType.create();
|
||||
}
|
||||
|
||||
function getTypeClassType(): ClassType | undefined {
|
||||
if (typeClass && isInstantiableClass(typeClass)) {
|
||||
return typeClass;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getTypingType(node: ParseNode, symbolName: string): Type | undefined {
|
||||
return (
|
||||
getTypeOfModule(node, symbolName, ['typing']) ?? getTypeOfModule(node, symbolName, ['typing_extensions'])
|
||||
@ -5720,7 +5727,7 @@ export function createTypeEvaluator(
|
||||
) {
|
||||
type = getDeclaredTypeOfSymbol(memberInfo.symbol)?.type;
|
||||
if (type && isInstantiableClass(memberInfo.classType)) {
|
||||
type = partiallySpecializeType(type, memberInfo.classType);
|
||||
type = partiallySpecializeType(type, memberInfo.classType, /* typeClassType */ undefined);
|
||||
}
|
||||
|
||||
// If we're setting a class variable via a write through an object,
|
||||
@ -6088,6 +6095,7 @@ export function createTypeEvaluator(
|
||||
const specializedType = partiallySpecializeType(
|
||||
methodType,
|
||||
accessMethodClass,
|
||||
getTypeClassType(),
|
||||
selfType ? (convertToInstantiable(selfType) as ClassType | TypeVarType) : classType
|
||||
);
|
||||
|
||||
@ -22308,8 +22316,8 @@ export function createTypeEvaluator(
|
||||
return partiallySpecializeType(
|
||||
getEffectiveTypeOfSymbol(member.symbol),
|
||||
member.classType,
|
||||
/* selfClass */ undefined,
|
||||
typeClass && isInstantiableClass(typeClass) ? typeClass : undefined
|
||||
getTypeClassType(),
|
||||
/* selfClass */ undefined
|
||||
);
|
||||
}
|
||||
return UnknownType.create();
|
||||
@ -22365,6 +22373,7 @@ export function createTypeEvaluator(
|
||||
const specializedType = partiallySpecializeType(
|
||||
typeResult.type,
|
||||
member.unspecializedClassType,
|
||||
getTypeClassType(),
|
||||
selfSpecializeClass(selfClass, { overrideTypeArgs: true })
|
||||
);
|
||||
|
||||
@ -22386,7 +22395,7 @@ export function createTypeEvaluator(
|
||||
}
|
||||
|
||||
return {
|
||||
type: partiallySpecializeType(typeResult.type, member.classType, selfClass),
|
||||
type: partiallySpecializeType(typeResult.type, member.classType, getTypeClassType(), selfClass),
|
||||
isIncomplete: !!typeResult.isIncomplete,
|
||||
};
|
||||
}
|
||||
@ -22637,7 +22646,7 @@ export function createTypeEvaluator(
|
||||
|
||||
let destMemberType = getEffectiveTypeOfSymbol(symbol);
|
||||
const srcMemberType = getTypeOfMember(memberInfo);
|
||||
destMemberType = partiallySpecializeType(destMemberType, destType);
|
||||
destMemberType = partiallySpecializeType(destMemberType, destType, getTypeClassType());
|
||||
|
||||
// Properties require special processing.
|
||||
if (
|
||||
@ -27401,6 +27410,7 @@ export function createTypeEvaluator(
|
||||
getObjectType,
|
||||
getNoneType,
|
||||
getUnionClassType,
|
||||
getTypeClassType,
|
||||
getBuiltInObject,
|
||||
getTypingType,
|
||||
assignTypeArguments,
|
||||
|
@ -651,6 +651,7 @@ export interface TypeEvaluator {
|
||||
getObjectType: () => Type;
|
||||
getNoneType: () => Type;
|
||||
getUnionClassType(): Type;
|
||||
getTypeClassType(): ClassType | undefined;
|
||||
getTypingType: (node: ParseNode, symbolName: string) => Type | undefined;
|
||||
inferReturnTypeIfNecessary: (type: Type) => void;
|
||||
inferTypeParameterVarianceForClass: (type: ClassType) => void;
|
||||
|
@ -1446,8 +1446,8 @@ export function isTupleIndexUnambiguous(type: ClassType, index: number) {
|
||||
export function partiallySpecializeType(
|
||||
type: Type,
|
||||
contextClassType: ClassType,
|
||||
selfClass?: ClassType | TypeVarType,
|
||||
typeClassType?: ClassType
|
||||
typeClassType: ClassType | undefined,
|
||||
selfClass?: ClassType | TypeVarType
|
||||
): Type {
|
||||
// If the context class is not specialized (or doesn't need specialization),
|
||||
// then there's no need to do any more work.
|
||||
@ -1477,8 +1477,8 @@ export function partiallySpecializeType(
|
||||
methodType: partiallySpecializeType(
|
||||
methodInfo.methodType,
|
||||
contextClassType,
|
||||
selfClass,
|
||||
typeClassType
|
||||
typeClassType,
|
||||
selfClass
|
||||
) as FunctionType,
|
||||
classType: methodInfo.classType,
|
||||
};
|
||||
@ -1965,7 +1965,7 @@ export function* getClassIterator(classType: Type, flags = ClassIteratorFlags.De
|
||||
|
||||
// If mroClass is an ancestor of classType, partially specialize
|
||||
// it in the context of classType.
|
||||
const specializedMroClass = partiallySpecializeType(mroClass, classType);
|
||||
const specializedMroClass = partiallySpecializeType(mroClass, classType, /* typeClassType */ undefined);
|
||||
|
||||
// Should we ignore members on the 'object' base class?
|
||||
if (flags & ClassIteratorFlags.SkipObjectBaseClass) {
|
||||
@ -2001,7 +2001,7 @@ export function getClassFieldsRecursive(classType: ClassType): Map<string, Class
|
||||
|
||||
// Evaluate the types of members from the end of the MRO to the beginning.
|
||||
ClassType.getReverseMro(classType).forEach((mroClass) => {
|
||||
const specializedMroClass = partiallySpecializeType(mroClass, classType);
|
||||
const specializedMroClass = partiallySpecializeType(mroClass, classType, /* typeClassType */ undefined);
|
||||
|
||||
if (isClass(specializedMroClass)) {
|
||||
ClassType.getSymbolTable(specializedMroClass).forEach((symbol, name) => {
|
||||
|
@ -974,7 +974,11 @@ function getTypedDictMembersForClassRecursive(
|
||||
|
||||
classType.shared.baseClasses.forEach((baseClassType) => {
|
||||
if (isInstantiableClass(baseClassType) && ClassType.isTypedDictClass(baseClassType)) {
|
||||
const specializedBaseClassType = partiallySpecializeType(baseClassType, classType);
|
||||
const specializedBaseClassType = partiallySpecializeType(
|
||||
baseClassType,
|
||||
classType,
|
||||
evaluator.getTypeClassType()
|
||||
);
|
||||
assert(isClass(specializedBaseClassType));
|
||||
|
||||
// Recursively gather keys from parent classes. Don't report any errors
|
||||
|
Loading…
Reference in New Issue
Block a user