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