diff --git a/packages/pyright-internal/src/analyzer/constraintTracker.ts b/packages/pyright-internal/src/analyzer/constraintTracker.ts index a0b2bd9b8b27..cb77fc493150 100644 --- a/packages/pyright-internal/src/analyzer/constraintTracker.ts +++ b/packages/pyright-internal/src/analyzer/constraintTracker.ts @@ -78,7 +78,7 @@ export class ConstraintSet { return type1 === type2; } - return isTypeSame(type1, type2); + return isTypeSame(type1, type2, { honorIsTypeArgExplicit: true, honorTypeForm: true }); } let isSame = true; diff --git a/packages/pyright-internal/src/analyzer/protocols.ts b/packages/pyright-internal/src/analyzer/protocols.ts index 4aca93317de7..7518a15b0d6e 100644 --- a/packages/pyright-internal/src/analyzer/protocols.ts +++ b/packages/pyright-internal/src/analyzer/protocols.ts @@ -257,8 +257,8 @@ function getProtocolCompatibility( } if ( - isTypeSame(entry.destType, destType) && - isTypeSame(entry.srcType, srcType) && + isTypeSame(entry.destType, destType, { honorIsTypeArgExplicit: true, honorTypeForm: true }) && + isTypeSame(entry.srcType, srcType, { honorIsTypeArgExplicit: true, honorTypeForm: true }) && isConstraintTrackerSame(constraints, entry.preConstraints) ) { return entry; diff --git a/packages/pyright-internal/src/analyzer/types.ts b/packages/pyright-internal/src/analyzer/types.ts index 099eab62cb41..535f93e4bf74 100644 --- a/packages/pyright-internal/src/analyzer/types.ts +++ b/packages/pyright-internal/src/analyzer/types.ts @@ -119,6 +119,7 @@ export interface TypeSameOptions { ignoreConditions?: boolean; ignoreTypedDictNarrowEntries?: boolean; honorTypeForm?: boolean; + honorIsTypeArgExplicit?: boolean; treatAnySameAsUnknown?: boolean; } @@ -3361,6 +3362,12 @@ export function isTypeSame(type1: Type, type2: Type, options: TypeSameOptions = return false; } + // This test is required for the "partial" class, which clones + // the symbol table to add a custom __call__ method. + if (type1.shared.fields !== classType2.shared.fields) { + return false; + } + if (!type1.priv.isUnpacked !== !classType2.priv.isUnpacked) { return false; } @@ -3369,6 +3376,12 @@ export function isTypeSame(type1: Type, type2: Type, options: TypeSameOptions = return false; } + if (options.honorIsTypeArgExplicit) { + if (!!type1.priv.isTypeArgExplicit !== !!classType2.priv.isTypeArgExplicit) { + return false; + } + } + if (!options.ignoreTypedDictNarrowEntries && !ClassType.isTypedDictNarrowedEntriesSame(type1, classType2)) { return false; } @@ -3502,6 +3515,10 @@ export function isTypeSame(type1: Type, type2: Type, options: TypeSameOptions = return false; } + if (type1.priv.nameWithScope !== type2TypeVar.priv.nameWithScope) { + return false; + } + // Handle the case where this is a generic recursive type alias. Make // sure that the type argument types match. if (type1.shared.recursiveAlias && type2TypeVar.shared.recursiveAlias) {