import { assert } from '../common/debug' ; import { ExpressionNode , ParameterCategory } from '../parser/parseNodes' ; import { FunctionDeclaration } from './declaration' ; import { Symbol , SymbolTable } from './symbol' ; export const enum TypeCategory { Unbound , Unknown , Any , None , Never , Function , OverloadedFunction , Class , Module , Union , TypeVar } export const enum TypeFlags { None = 0 , Instantiable = 1 << 0 , Instance = 1 << 1 , Annotated = 1 << 2 , SpecialForm = 1 << 3 } export type UnionableType = UnboundType | UnknownType | AnyType | NoneType | FunctionType | OverloadedFunctionType | ClassType | ModuleType | TypeVarType ; export type Type = UnionableType | NeverType | UnionType ; export type TypeVarScopeId = string ; export const WildcardTypeVarScopeId = '*' ; export class EnumLiteral { constructor ( public className , public itemName , public itemType ) { } } export type LiteralValue = number | boolean | string | EnumLiteral ; export type TypeSourceId = number ; export const maxTypeRecursionCount = 16 ; export type InheritanceChain = ( ClassType | UnknownType ) [ ] ; interface TypeAliasInfo { name : string ; fullName : string ; typeParameters ? : TypeVarType [ ] | undefined ; typeArguments ? : Type [ ] | undefined ; typeVarScopeId : TypeVarScopeId ; } interface TypeBase { category : TypeCategory ; flags : TypeFlags ; typeAliasInfo ? : TypeAliasInfo | undefined ; condition ? : TypeCondition [ ] | undefined ; } export namespace TypeBase { export function isInstantiable ( type ) { return ( type . flags & TypeFlags . Instantiable ) !== 0 ; } export function isInstance ( type ) { return ( type . flags & TypeFlags . Instance ) !== 0 ; } export function isAnnotated ( type ) { return ( type . flags & TypeFlags . Annotated ) !== 0 ; } export function isSpecialForm ( type ) { return ( type . flags & TypeFlags . SpecialForm ) !== 0 ; } export function setSpecialForm ( type ) { return ( type . flags |= TypeFlags . SpecialForm ) ; } export function cloneForTypeAlias ( type , name , fullName , typeVarScopeId , typeParams ? , typeArgs ? ) { const typeClone = { ... type } ; typeClone . typeAliasInfo = { name , fullName , typeParameters : typeParams , typeArguments : typeArgs , typeVarScopeId , } ; return typeClone ; } export function cloneForAnnotated ( type ) { const typeClone = { ... type } ; typeClone . flags |= TypeFlags . Annotated ; return typeClone ; } export function cloneForCondition < T extends Type > ( type , condition ) { if ( type . condition === undefined && condition === undefined ) { return type ; } const typeClone = { ... type } ; typeClone . condition = condition ; return typeClone ; } } export interface UnboundType extends TypeBase { category : TypeCategory . Unbound ; } export namespace UnboundType { const _instance = { category : TypeCategory . Unbound , flags : TypeFlags . Instantiable | TypeFlags . Instance , } ; export function create ( ) { return _instance ; } } export interface UnknownType extends TypeBase { category : TypeCategory . Unknown ; } export namespace UnknownType { const _instance = { category : TypeCategory . Unknown , flags : TypeFlags . Instantiable | TypeFlags . Instance , } ; export function create ( ) { return _instance ; } } export interface ModuleType extends TypeBase { category : TypeCategory . Module ; fields : SymbolTable ; docString ? : string | undefined ; loaderFields : SymbolTable ; moduleName : string ; filePath : string ; } export namespace ModuleType { export function create ( moduleName , filePath , symbolTable ? ) { const newModuleType = { category : TypeCategory . Module , fields : symbolTable || new Map < string , Symbol > ( ) , loaderFields : new Map < string , Symbol > ( ) , flags : TypeFlags . Instantiable | TypeFlags . Instantiable , moduleName , filePath , } ; return newModuleType ; } export function getField ( moduleType , name ) { let symbol = moduleType . fields . get ( name ) ; if ( moduleType . loaderFields ) { if ( ! symbol ) { symbol = moduleType . loaderFields . get ( name ) ; } else if ( symbol . isExternallyHidden ( ) ) { const loaderSymbol = moduleType . loaderFields . get ( name ) ; if ( loaderSymbol && ! loaderSymbol . isExternallyHidden ( ) ) { symbol = loaderSymbol ; } } } return symbol ; } } export interface DataClassEntry { name : string ; isClassVar : boolean ; isKeywordOnly : boolean ; alias ? : string | undefined ; hasDefault ? : boolean | undefined ; defaultValueExpression ? : ExpressionNode | undefined ; includeInInit : boolean ; type : Type ; } export interface TypedDictEntry { valueType : Type ; isRequired : boolean ; isProvided : boolean ; } export const enum ClassTypeFlags { None = 0 , BuiltInClass = 1 << 0 , SpecialBuiltIn = 1 << 1 , DataClass = 1 << 2 , FrozenDataClass = 1 << 3 , SkipSynthesizedDataClassInit = 1 << 4 , SkipSynthesizedDataClassEq = 1 << 5 , SynthesizedDataClassOrder = 1 << 6 , TypedDictClass = 1 << 7 , CanOmitDictValues = 1 << 8 , SupportsAbstractMethods = 1 << 9 , PropertyClass = 1 << 11 , Final = 1 << 12 , ProtocolClass = 1 << 13 , PseudoGenericClass = 1 << 14 , RuntimeCheckable = 1 << 15 , TypingExtensionClass = 1 << 16 , PartiallyConstructed = 1 << 17 , HasCustomClassGetItem = 1 << 18 , TupleClass = 1 << 19 , EnumClass = 1 << 20 , DataClassKeywordOnlyParams = 1 << 21 , ClassProperty = 1 << 22 , DefinedInStub = 1 << 23 , ReadOnlyInstanceVariables = 1 << 24 , GenerateDataClassSlots = 1 << 25 , SynthesizeDataClassUnsafeHash = 1 << 26 } export interface DataClassBehaviors { keywordOnlyParams : boolean ; generateEq : boolean ; generateOrder : boolean ; fieldDescriptorNames : string [ ] ; } interface ClassDetails { name : string ; fullName : string ; moduleName : string ; filePath : string ; flags : ClassTypeFlags ; typeSourceId : TypeSourceId ; baseClasses : Type [ ] ; mro : Type [ ] ; declaredMetaclass ? : ClassType | UnknownType | undefined ; effectiveMetaclass ? : ClassType | UnknownType | undefined ; fields : SymbolTable ; typeParameters : TypeVarType [ ] ; typeVarScopeId ? : TypeVarScopeId | undefined ; docString ? : string | undefined ; dataClassEntries ? : DataClassEntry [ ] | undefined ; dataClassBehaviors ? : DataClassBehaviors | undefined ; typedDictEntries ? : Map < string , TypedDictEntry > | undefined ; inheritedSlotsNames ? : string [ ] ; localSlotsNames ? : string [ ] ; metaclassDataClassTransform ? : DataClassBehaviors | undefined ; } export interface ClassType extends TypeBase { category : TypeCategory . Class ; details : ClassDetails ; typeArguments ? : Type [ ] | undefined ; positiveTypeGuardType ? : Type | undefined ; negativeTypeGuardType ? : Type | undefined ; isEmptyContainer ? : boolean | undefined ; tupleTypeArguments ? : Type [ ] | undefined ; isTupleForUnpackedVariadicTypeVar ? : boolean | undefined ; isTypeArgumentExplicit ? : boolean | undefined ; includeSubclasses ? : boolean ; literalValue ? : LiteralValue | undefined ; aliasName ? : string | undefined ; typedDictNarrowedEntries ? : Map < string , TypedDictEntry > | undefined ; isAsymmetricDescriptor ? : boolean ; } export namespace ClassType { export function createInstantiable ( name , fullName , moduleName , filePath , flags , typeSourceId , declaredMetaclass , effectiveMetaclass , docString ? ) { const newClass = { category : TypeCategory . Class , details : { name , fullName , moduleName , filePath , flags , typeSourceId , baseClasses : [ ] , declaredMetaclass , effectiveMetaclass , mro : [ ] , fields : new Map < string , Symbol > ( ) , typeParameters : [ ] , docString , } , flags : TypeFlags . Instantiable , } ; return newClass ; } export function cloneAsInstance ( classType ) { if ( TypeBase . isInstance ( classType ) ) { return classType ; } const objectType = { ... classType } ; objectType . flags &= ~ ( TypeFlags . Instantiable | TypeFlags . SpecialForm ) ; objectType . flags |= TypeFlags . Instance ; objectType . includeSubclasses = true ; return objectType ; } export function cloneAsInstantiable ( objectType ) { if ( TypeBase . isInstantiable ( objectType ) ) { return objectType ; } const classType = { ... objectType } ; classType . flags &= ~ TypeFlags . Instance ; classType . flags |= TypeFlags . Instantiable ; return classType ; } export function cloneForSpecialization ( classType , typeArguments , isTypeArgumentExplicit , includeSubclasses = false , tupleTypeArguments ? , isEmptyContainer ? ) { const newClassType = { ... classType } ; newClassType . typeArguments = typeArguments ? typeArguments . map ( ( t ) => ( isNever ( t ) ? UnknownType . create ( ) : t ) ) : undefined ; newClassType . isTypeArgumentExplicit = isTypeArgumentExplicit ; if ( includeSubclasses ) { newClassType . includeSubclasses = true ; } newClassType . tupleTypeArguments = tupleTypeArguments ? tupleTypeArguments . map ( ( t ) => ( isNever ( t ) ? UnknownType . create ( ) : t ) ) : undefined ; if ( isEmptyContainer !== undefined ) { newClassType . isEmptyContainer = isEmptyContainer ; } return newClassType ; } export function cloneWithLiteral ( classType , value ) { const newClassType = { ... classType } ; newClassType . literalValue = value ; return newClassType ; } export function cloneForTypingAlias ( classType , aliasName ) { const newClassType = { ... classType } ; newClassType . aliasName = aliasName ; return newClassType ; } export function cloneForNarrowedTypedDictEntries ( classType , narrowedEntries ? ) { const newClassType = { ... classType } ; newClassType . typedDictNarrowedEntries = narrowedEntries ; return newClassType ; } export function cloneWithNewTypeParameters ( classType , typeParams ) { const newClassType = { ... classType } ; newClassType . details = { ... newClassType . details } ; newClassType . details . typeParameters = typeParams ; return newClassType ; } export function cloneForTypeGuard ( classType , positiveTypeGuardType , negativeTypeGuardType ) { const newClassType = { ... classType } ; newClassType . positiveTypeGuardType = positiveTypeGuardType ; if ( negativeTypeGuardType ) { newClassType . negativeTypeGuardType = negativeTypeGuardType ; } return newClassType ; } export function cloneForSymbolTableUpdate ( classType ) { const newClassType = { ... classType } ; newClassType . details = { ... newClassType . details } ; newClassType . details . fields = new Map ( newClassType . details . fields ) ; newClassType . details . mro = [ ... newClassType . details . mro ] ; newClassType . details . mro [ 0 ] = cloneAsInstantiable ( newClassType ) ; return newClassType ; } export function isLiteralValueSame ( type1 , type2 ) { if ( type1 . literalValue === undefined ) { return type2 . literalValue === undefined ; } else if ( type2 . literalValue === undefined ) { return false ; } if ( type1 . literalValue instanceof EnumLiteral ) { if ( type2 . literalValue instanceof EnumLiteral ) { return type1 . literalValue . itemName === type2 . literalValue . itemName ; } return false ; } return type1 . literalValue === type2 . literalValue ; } export function isUnspecialized ( classType ) { return classType . details . typeParameters . length > 0 && classType . typeArguments === undefined ; } export function isSpecialBuiltIn ( classType , className ? ) { if ( ! ( classType . details . flags & ClassTypeFlags . SpecialBuiltIn ) && ! classType . aliasName ) { return false ; } if ( className !== undefined ) { return classType . details . name === className ; } return true ; } export function isBuiltIn ( classType , className ? ) { if ( ! ( classType . details . flags & ClassTypeFlags . BuiltInClass ) ) { return false ; } if ( className !== undefined ) { return classType . details . name === className || classType . aliasName === className ; } return true ; } export function supportsAbstractMethods ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . SupportsAbstractMethods ) ; } export function isDataClass ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . DataClass ) ; } export function isSkipSynthesizedDataClassInit ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . SkipSynthesizedDataClassInit ) ; } export function isSkipSynthesizedDataClassEq ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . SkipSynthesizedDataClassEq ) ; } export function isFrozenDataClass ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . FrozenDataClass ) ; } export function isSynthesizedDataclassOrder ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . SynthesizedDataClassOrder ) ; } export function isDataClassKeywordOnlyParams ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . DataClassKeywordOnlyParams ) ; } export function isGeneratedDataClassSlots ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . GenerateDataClassSlots ) ; } export function isSynthesizeDataClassUnsafeHash ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . SynthesizeDataClassUnsafeHash ) ; } export function isTypedDictClass ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . TypedDictClass ) ; } export function isCanOmitDictValues ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . CanOmitDictValues ) ; } export function isEnumClass ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . EnumClass ) ; } export function isPropertyClass ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . PropertyClass ) ; } export function isClassProperty ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . ClassProperty ) ; } export function isFinal ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . Final ) ; } export function isProtocolClass ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . ProtocolClass ) ; } export function isDefinedInStub ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . DefinedInStub ) ; } export function isPseudoGenericClass ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . PseudoGenericClass ) ; } export function getDataClassEntries ( classType ) { return classType . details . dataClassEntries || [ ] ; } export function isRuntimeCheckable ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . RuntimeCheckable ) ; } export function isTypingExtensionClass ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . TypingExtensionClass ) ; } export function isPartiallyConstructed ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . PartiallyConstructed ) ; } export function hasCustomClassGetItem ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . HasCustomClassGetItem ) ; } export function isTupleClass ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . TupleClass ) ; } export function isReadOnlyInstanceVariables ( classType ) { return ! ! ( classType . details . flags & ClassTypeFlags . ReadOnlyInstanceVariables ) ; } export function getTypeParameters ( classType ) { return classType . details . typeParameters ; } export function hasUnknownBaseClass ( classType ) { return classType . details . mro . some ( ( baseClass ) => isAnyOrUnknown ( baseClass ) ) ; } export function isSameGenericClass ( classType , type2 , recursionCount = 0 ) { if ( recursionCount > maxTypeRecursionCount ) { return true ; } if ( classType . details === type2 . details ) { return true ; } const class1Details = classType . details ; const class2Details = type2 . details ; if ( class1Details === class2Details ) { return true ; } if ( class1Details . fullName !== class2Details . fullName || class1Details . flags !== class2Details . flags || class1Details . typeSourceId !== class2Details . typeSourceId || class1Details . baseClasses . length !== class2Details . baseClasses . length || class1Details . typeParameters . length !== class2Details . typeParameters . length ) { return false ; } if ( ClassType . isBuiltIn ( classType , 'NamedTuple' ) && ClassType . isBuiltIn ( type2 , 'NamedTuple' ) ) { return true ; } if ( ClassType . isBuiltIn ( classType , 'tuple' ) && ClassType . isBuiltIn ( type2 , 'tuple' ) ) { return true ; } for ( let i = 0 ; i < class1Details . baseClasses . length ; i ++ ) { if ( ! isTypeSame ( class1Details . baseClasses [ i ] , class2Details . baseClasses [ i ] , true , undefined , recursionCount + 1 ) ) { return false ; } } if ( class1Details . declaredMetaclass || class2Details . declaredMetaclass ) { if ( ! class1Details . declaredMetaclass || ! class2Details . declaredMetaclass || ! isTypeSame ( class1Details . declaredMetaclass , class2Details . declaredMetaclass , true , undefined , recursionCount + 1 ) ) { return false ; } } for ( let i = 0 ; i < class1Details . typeParameters . length ; i ++ ) { if ( ! isTypeSame ( class1Details . typeParameters [ i ] , class2Details . typeParameters [ i ] , true , undefined , recursionCount + 1 ) ) { return false ; } } return true ; } export function isDerivedFrom ( subclassType , parentClassType , inheritanceChain ? ) { if ( isSameGenericClass ( subclassType , parentClassType ) ) { if ( inheritanceChain ) { inheritanceChain . push ( subclassType ) ; } return true ; } if ( isBuiltIn ( subclassType ) && isBuiltIn ( parentClassType , 'object' ) ) { if ( inheritanceChain ) { inheritanceChain . push ( parentClassType ) ; } return true ; } for ( const baseClass of subclassType . details . baseClasses ) { if ( isInstantiableClass ( baseClass ) ) { if ( isDerivedFrom ( baseClass , parentClassType , inheritanceChain ) ) { if ( inheritanceChain ) { inheritanceChain . push ( subclassType ) ; } return true ; } } else if ( isAnyOrUnknown ( baseClass ) ) { if ( inheritanceChain ) { inheritanceChain . push ( UnknownType . create ( ) ) ; } return true ; } } return false ; } } export interface ParamSpecEntry { category : ParameterCategory ; name ? : string | undefined ; isNameSynthesized ? : boolean ; hasDefault ? : boolean | undefined ; type : Type ; } export interface FunctionParameter extends ParamSpecEntry { isTypeInferred ? : boolean | undefined ; defaultValueExpression ? : ExpressionNode | undefined ; defaultType ? : Type | undefined ; hasDeclaredType ? : boolean | undefined ; typeAnnotation ? : ExpressionNode | undefined ; } export const enum FunctionTypeFlags { None = 0 , ConstructorMethod = 1 << 0 , ClassMethod = 1 << 1 , StaticMethod = 1 << 2 , AbstractMethod = 1 << 3 , Generator = 1 << 4 , DisableDefaultChecks = 1 << 5 , SynthesizedMethod = 1 << 6 , SkipConstructorCheck = 1 << 7 , Overloaded = 1 << 8 , Async = 1 << 9 , WrapReturnTypeInAwait = 1 << 10 , StubDefinition = 1 << 11 , PyTypedDefinition = 1 << 12 , Final = 1 << 13 , UnannotatedParams = 1 << 14 , SkipArgsKwargsCompatibilityCheck = 1 << 15 , ParamSpecValue = 1 << 16 } interface FunctionDetails { name : string ; fullName : string ; moduleName : string ; flags : FunctionTypeFlags ; parameters : FunctionParameter [ ] ; declaredReturnType ? : Type | undefined ; declaration ? : FunctionDeclaration | undefined ; typeVarScopeId ? : TypeVarScopeId | undefined ; builtInName ? : string | undefined ; docString ? : string | undefined ; decoratorDataClassBehaviors ? : DataClassBehaviors | undefined ; paramSpec ? : TypeVarType | undefined ; } export interface SpecializedFunctionTypes { parameterTypes : Type [ ] ; returnType ? : Type | undefined ; } export interface FunctionType extends TypeBase { category : TypeCategory . Function ; details : FunctionDetails ; specializedTypes ? : SpecializedFunctionTypes | undefined ; inferredReturnType ? : Type | undefined ; strippedFirstParamType ? : Type | undefined ; boundToType ? : ClassType | undefined ; preBoundFlags ? : FunctionTypeFlags ; boundTypeVarScopeId ? : TypeVarScopeId | undefined ; } export interface ParamSpecValue { flags : FunctionTypeFlags ; parameters : ParamSpecEntry [ ] ; docString : string | undefined ; paramSpec : TypeVarType | undefined ; } export namespace FunctionType { export function createInstance ( name , fullName , moduleName , functionFlags , docString ? ) { return create ( name , fullName , moduleName , functionFlags , TypeFlags . Instance , docString ) ; } export function createInstantiable ( name , fullName , moduleName , functionFlags , docString ? ) { return create ( name , fullName , moduleName , functionFlags , TypeFlags . Instantiable , docString ) ; } function create ( name , fullName , moduleName , functionFlags , typeFlags , docString ? ) { const newFunctionType = { category : TypeCategory . Function , details : { name , fullName , moduleName , flags : functionFlags , parameters : [ ] , docString , } , flags : typeFlags , } ; return newFunctionType ; } export function clone ( type , stripFirstParam = false , boundToType ? , boundTypeVarScopeId ? ) { const newFunction = create ( type . details . name , type . details . fullName , type . details . moduleName , type . details . flags , type . flags , type . details . docString ) ; newFunction . details = { ... type . details } ; newFunction . boundToType = boundToType ; newFunction . preBoundFlags = newFunction . details . flags ; if ( stripFirstParam ) { if ( type . details . parameters . length > 0 && type . details . parameters [ 0 ] . category === ParameterCategory . Simple ) { if ( type . details . parameters . length > 0 && ! type . details . parameters [ 0 ] . isTypeInferred ) { newFunction . strippedFirstParamType = getEffectiveParameterType ( type , 0 ) ; } newFunction . details . parameters = type . details . parameters . slice ( 1 ) ; } else { stripFirstParam = false ; } newFunction . details . flags &= ~ ( FunctionTypeFlags . ConstructorMethod | FunctionTypeFlags . ClassMethod ) ; newFunction . details . flags |= FunctionTypeFlags . StaticMethod ; } if ( type . typeAliasInfo !== undefined ) { newFunction . typeAliasInfo = type . typeAliasInfo ; } if ( type . specializedTypes ) { newFunction . specializedTypes = { parameterTypes : stripFirstParam ? type . specializedTypes . parameterTypes . slice ( 1 ) : type . specializedTypes . parameterTypes , returnType : type . specializedTypes . returnType , } ; } newFunction . inferredReturnType = type . inferredReturnType ; newFunction . boundTypeVarScopeId = boundTypeVarScopeId ; return newFunction ; } export function cloneAsInstance ( type ) { assert ( TypeBase . isInstantiable ( type ) ) ; const newInstance = { ... type } ; newInstance . flags &= ~ ( TypeFlags . Instantiable | TypeFlags . SpecialForm ) ; newInstance . flags |= TypeFlags . Instance ; return newInstance ; } export function cloneAsInstantiable ( type ) { assert ( TypeBase . isInstance ( type ) ) ; const newInstance = { ... type } ; newInstance . flags &= ~ ( TypeFlags . Instance | TypeFlags . SpecialForm ) ; newInstance . flags |= TypeFlags . Instantiable ; return newInstance ; } export function cloneForSpecialization ( type , specializedTypes , specializedInferredReturnType ) { const newFunction = create ( type . details . name , type . details . fullName , type . details . moduleName , type . details . flags , type . flags , type . details . docString ) ; newFunction . details = type . details ; assert ( specializedTypes . parameterTypes . length === type . details . parameters . length ) ; newFunction . specializedTypes = specializedTypes ; if ( specializedInferredReturnType ) { newFunction . inferredReturnType = specializedInferredReturnType ; } return newFunction ; } export function cloneForParamSpec ( type , paramSpecValue ) { const newFunction = create ( type . details . name , type . details . fullName , type . details . moduleName , type . details . flags , type . flags , type . details . docString ) ; newFunction . specializedTypes = type . specializedTypes ; newFunction . details = { ... type . details } ; delete newFunction . details . paramSpec ; if ( paramSpecValue ) { newFunction . details . parameters = [ ... type . details . parameters , ... paramSpecValue . parameters . map ( ( specEntry ) => { return { category : specEntry . category , name : specEntry . name , hasDefault : specEntry . hasDefault , isNameSynthesized : specEntry . isNameSynthesized , hasDeclaredType : true , type : specEntry . type , } ; } ) , ] ; if ( ! newFunction . details . docString ) { newFunction . details . docString = paramSpecValue . docString ; } newFunction . details . flags = ( paramSpecValue . flags & ( FunctionTypeFlags . ClassMethod | FunctionTypeFlags . StaticMethod | FunctionTypeFlags . ConstructorMethod | FunctionTypeFlags . SkipArgsKwargsCompatibilityCheck | FunctionTypeFlags . ParamSpecValue ) ) | FunctionTypeFlags . SynthesizedMethod ; if ( FunctionType . isParamSpecValue ( type ) ) { newFunction . details . flags |= FunctionTypeFlags . ParamSpecValue ; } if ( newFunction . specializedTypes ) { paramSpecValue . parameters . forEach ( ( paramInfo ) => { newFunction . specializedTypes ! . parameterTypes . push ( paramInfo . type ) ; } ) ; } newFunction . details . paramSpec = paramSpecValue . paramSpec ; } return newFunction ; } export function cloneForParamSpecApplication ( type , paramSpecValue ) { const newFunction = { ... type } ; newFunction . details = { ... type . details } ; newFunction . details . parameters = newFunction . details . parameters . slice ( 0 , newFunction . details . parameters . length - 2 ) ; paramSpecValue . parameters . forEach ( ( specEntry ) => { newFunction . details . parameters . push ( { category : specEntry . category , name : specEntry . name , hasDefault : specEntry . hasDefault , isNameSynthesized : specEntry . isNameSynthesized , hasDeclaredType : true , type : specEntry . type , } ) ; } ) ; newFunction . details . paramSpec = paramSpecValue . paramSpec ; if ( ! newFunction . details . docString ) { newFunction . details . docString = paramSpecValue . docString ; } return newFunction ; } export function cloneRemoveParamSpecVariadics ( type , paramSpec ) { const newFunction = create ( type . details . name , type . details . fullName , type . details . moduleName , type . details . flags , type . flags , type . details . docString ) ; newFunction . details = { ... type . details } ; newFunction . details . parameters = newFunction . details . parameters . slice ( 0 , newFunction . details . parameters . length - 2 ) ; if ( type . specializedTypes ) { newFunction . specializedTypes = { ... type . specializedTypes } ; newFunction . specializedTypes . parameterTypes = newFunction . specializedTypes . parameterTypes . slice ( 0 , newFunction . specializedTypes . parameterTypes . length - 2 ) ; } if ( ! newFunction . details . paramSpec ) { newFunction . details . paramSpec = paramSpec ; } return newFunction ; } export function addDefaultParameters ( functionType , useUnknown = false ) { FunctionType . addParameter ( functionType , { category : ParameterCategory . VarArgList , name : 'args' , type : useUnknown ? UnknownType . create ( ) : AnyType . create ( ) , hasDeclaredType : ! useUnknown , } ) ; FunctionType . addParameter ( functionType , { category : ParameterCategory . VarArgDictionary , name : 'kwargs' , type : useUnknown ? UnknownType . create ( ) : AnyType . create ( ) , hasDeclaredType : ! useUnknown , } ) ; } export function isInstanceMethod ( type ) { return ( ( type . details . flags & ( FunctionTypeFlags . ConstructorMethod | FunctionTypeFlags . StaticMethod | FunctionTypeFlags . ClassMethod ) ) === 0 ) ; } export function isConstructorMethod ( type ) { return ( type . details . flags & FunctionTypeFlags . ConstructorMethod ) !== 0 ; } export function isStaticMethod ( type ) { return ( type . details . flags & FunctionTypeFlags . StaticMethod ) !== 0 ; } export function isClassMethod ( type ) { return ( type . details . flags & FunctionTypeFlags . ClassMethod ) !== 0 ; } export function isAbstractMethod ( type ) { return ( type . details . flags & FunctionTypeFlags . AbstractMethod ) !== 0 ; } export function isGenerator ( type ) { return ( type . details . flags & FunctionTypeFlags . Generator ) !== 0 ; } export function isSynthesizedMethod ( type ) { return ( type . details . flags & FunctionTypeFlags . SynthesizedMethod ) !== 0 ; } export function isSkipConstructorCheck ( type ) { return ( type . details . flags & FunctionTypeFlags . SkipConstructorCheck ) !== 0 ; } export function isOverloaded ( type ) { return ( type . details . flags & FunctionTypeFlags . Overloaded ) !== 0 ; } export function isDefaultParameterCheckDisabled ( type ) { return ( type . details . flags & FunctionTypeFlags . DisableDefaultChecks ) !== 0 ; } export function isAsync ( type ) { return ( type . details . flags & FunctionTypeFlags . Async ) !== 0 ; } export function isWrapReturnTypeInAwait ( type ) { return ( type . details . flags & FunctionTypeFlags . WrapReturnTypeInAwait ) !== 0 ; } export function isStubDefinition ( type ) { return ( type . details . flags & FunctionTypeFlags . StubDefinition ) !== 0 ; } export function isPyTypedDefinition ( type ) { return ( type . details . flags & FunctionTypeFlags . PyTypedDefinition ) !== 0 ; } export function isFinal ( type ) { return ( type . details . flags & FunctionTypeFlags . Final ) !== 0 ; } export function hasUnannotatedParams ( type ) { return ( type . details . flags & FunctionTypeFlags . UnannotatedParams ) !== 0 ; } export function shouldSkipArgsKwargsCompatibilityCheck ( type ) { return ( type . details . flags & FunctionTypeFlags . SkipArgsKwargsCompatibilityCheck ) !== 0 ; } export function isParamSpecValue ( type ) { return ( type . details . flags & FunctionTypeFlags . ParamSpecValue ) !== 0 ; } export function getEffectiveParameterType ( type , index ) { assert ( index < type . details . parameters . length ) ; if ( type . specializedTypes ) { assert ( index < type . specializedTypes . parameterTypes . length ) ; return type . specializedTypes . parameterTypes [ index ] ; } return type . details . parameters [ index ] . type ; } export function addParameter ( type , param ) { type . details . parameters . push ( param ) ; } export function getSpecializedReturnType ( type ) { return type . specializedTypes && type . specializedTypes . returnType ? type . specializedTypes . returnType : type . details . declaredReturnType ; } } export interface OverloadedFunctionType extends TypeBase { category : TypeCategory . OverloadedFunction ; overloads : FunctionType [ ] ; } export namespace OverloadedFunctionType { export function create ( overloads ) { const newType = { category : TypeCategory . OverloadedFunction , overloads , flags : TypeFlags . Instance , } ; return newType ; } export function addOverload ( type , functionType ) { type . overloads . push ( functionType ) ; } } export interface NoneType extends TypeBase { category : TypeCategory . None ; } export namespace NoneType { const _noneInstance = { category : TypeCategory . None , flags : TypeFlags . Instance , } ; const _noneType = { category : TypeCategory . None , flags : TypeFlags . Instantiable , } ; export function createInstance ( ) { return _noneInstance ; } export function createType ( ) { return _noneType ; } } export interface NeverType extends TypeBase { category : TypeCategory . Never ; } export namespace NeverType { const _neverInstance = { category : TypeCategory . Never , flags : TypeFlags . Instance | TypeFlags . Instantiable , } ; export function create ( ) { return _neverInstance ; } } export interface AnyType extends TypeBase { category : TypeCategory . Any ; isEllipsis : boolean ; } export namespace AnyType { const _anyInstance = { category : TypeCategory . Any , isEllipsis : false , flags : TypeFlags . Instance | TypeFlags . Instantiable , } ; const _ellipsisInstance = { category : TypeCategory . Any , isEllipsis : true , flags : TypeFlags . Instance | TypeFlags . Instantiable , } ; export function create ( isEllipsis = false ) { return isEllipsis ? _ellipsisInstance : _anyInstance ; } } export interface TypeCondition { typeVarName : string ; constraintIndex : number ; isConstrainedTypeVar : boolean ; } export namespace TypeCondition { export function combine ( conditions1 , conditions2 ) { if ( ! conditions1 ) { return conditions2 ; } if ( ! conditions2 ) { return conditions1 ; } const combined = [ ... conditions1 ] ; conditions2 . forEach ( ( c1 ) => { if ( ! combined . some ( ( c2 ) => _compare ( c1 , c2 ) === 0 ) ) { combined . push ( c1 ) ; } } ) ; return combined . sort ( _compare ) ; } function _compare ( c1 , c2 ) { if ( c1 . typeVarName < c2 . typeVarName ) { return - 1 ; } else if ( c1 . typeVarName > c2 . typeVarName ) { return 1 ; } if ( c1 . constraintIndex < c2 . constraintIndex ) { return - 1 ; } else if ( c1 . constraintIndex > c2 . constraintIndex ) { return 1 ; } return 0 ; } export function isSame ( conditions1 , conditions2 ) { if ( ! conditions1 ) { return ! conditions2 ; } if ( ! conditions2 || conditions1 . length !== conditions2 . length ) { return false ; } return ( conditions1 . find ( ( c1 , index ) => c1 . typeVarName !== conditions2 [ index ] . typeVarName || c1 . constraintIndex !== conditions2 [ index ] . constraintIndex ) === undefined ) ; } export function isCompatible ( conditions1 , conditions2 ) { if ( ! conditions1 || ! conditions2 ) { return true ; } for ( const c1 of conditions1 ) { let foundTypeVarMatch = false ; const exactMatch = conditions2 . find ( ( c2 ) => { if ( c1 . typeVarName === c2 . typeVarName ) { foundTypeVarMatch = true ; return c1 . constraintIndex === c2 . constraintIndex ; } return false ; } ) ; if ( foundTypeVarMatch && ! exactMatch ) { return false ; } } return true ; } } export interface UnionType extends TypeBase { category : TypeCategory . Union ; subtypes : UnionableType [ ] ; literalStrMap ? : Map < string , UnionableType > | undefined ; literalIntMap ? : Map < number , UnionableType > | undefined ; typeAliasSources ? : Set < UnionType > ; } export namespace UnionType { export function create ( ) { const newUnionType = { category : TypeCategory . Union , subtypes : [ ] , flags : TypeFlags . Instance | TypeFlags . Instantiable , } ; return newUnionType ; } export function addType ( unionType , newType ) { if ( isClassInstance ( newType ) && ClassType . isBuiltIn ( newType , 'str' ) && newType . literalValue !== undefined && newType . condition === undefined ) { if ( unionType . literalStrMap === undefined ) { unionType . literalStrMap = new Map < string , UnionableType > ( ) ; } unionType . literalStrMap . set ( newType . literalValue as string , newType ) ; } else if ( isClassInstance ( newType ) && ClassType . isBuiltIn ( newType , 'int' ) && newType . literalValue !== undefined && newType . condition === undefined ) { if ( unionType . literalIntMap === undefined ) { unionType . literalIntMap = new Map < number , UnionableType > ( ) ; } unionType . literalIntMap . set ( newType . literalValue as number , newType ) ; } unionType . flags &= newType . flags ; unionType . subtypes . push ( newType ) ; } export function containsType ( unionType , subtype , recursionCount = 0 ) { if ( isClassInstance ( subtype ) && subtype . condition === undefined ) { if ( ClassType . isBuiltIn ( subtype , 'str' ) && subtype . literalValue !== undefined && unionType . literalStrMap !== undefined ) { return unionType . literalStrMap . has ( subtype . literalValue as string ) ; } else if ( ClassType . isBuiltIn ( subtype , 'int' ) && subtype . literalValue !== undefined && unionType . literalIntMap !== undefined ) { return unionType . literalIntMap . has ( subtype . literalValue as number ) ; } } return ( unionType . subtypes . find ( ( t ) => isTypeSame ( t , subtype , undefined , undefined , recursionCount + 1 ) ) !== undefined ) ; } export function addTypeAliasSource ( unionType , typeAliasSource ) { if ( typeAliasSource . category === TypeCategory . Union ) { const sourcesToAdd = typeAliasSource . typeAliasInfo ? [ typeAliasSource ] : typeAliasSource . typeAliasSources ; if ( sourcesToAdd ) { if ( ! unionType . typeAliasSources ) { unionType . typeAliasSources = new Set < UnionType > ( ) ; } sourcesToAdd . forEach ( ( source ) => { unionType . typeAliasSources ! . add ( source ) ; } ) ; } } } } export const enum Variance { Invariant , Covariant , Contravariant } export interface TypeVarDetails { name : string ; constraints : Type [ ] ; boundType ? : Type | undefined ; variance : Variance ; isParamSpec : boolean ; isVariadic : boolean ; isSynthesized : boolean ; isSynthesizedSelf ? : boolean | undefined ; synthesizedIndex ? : number | undefined ; isExemptFromBoundCheck ? : boolean ; recursiveTypeAliasName ? : string | undefined ; recursiveTypeAliasScopeId ? : TypeVarScopeId | undefined ; illegalRecursionDetected ? : boolean | undefined ; recursiveTypeParameters ? : TypeVarType [ ] | undefined ; } export type ParamSpecAccess = 'args' | 'kwargs' ; export const enum TypeVarScopeType { Class , Function , TypeAlias } export interface TypeVarType extends TypeBase { category : TypeCategory . TypeVar ; details : TypeVarDetails ; scopeId ? : TypeVarScopeId | undefined ; scopeName ? : string | undefined ; scopeType ? : TypeVarScopeType ; nameWithScope ? : string | undefined ; isVariadicUnpacked ? : boolean | undefined ; isVariadicInUnion ? : boolean | undefined ; paramSpecAccess ? : ParamSpecAccess ; } export namespace TypeVarType { export function createInstance ( name ) { return create ( name , false , TypeFlags . Instance ) ; } export function createInstantiable ( name , isParamSpec = false ) { return create ( name , isParamSpec , TypeFlags . Instantiable ) ; } export function cloneAsInstance ( type ) { assert ( TypeBase . isInstantiable ( type ) ) ; const newInstance = { ... type } ; newInstance . flags &= ~ ( TypeFlags . Instantiable | TypeFlags . SpecialForm ) ; newInstance . flags |= TypeFlags . Instance ; return newInstance ; } export function cloneAsInstantiable ( type ) { assert ( TypeBase . isInstance ( type ) ) ; const newInstance = { ... type } ; newInstance . flags &= ~ ( TypeFlags . Instance | TypeFlags . SpecialForm ) ; newInstance . flags |= TypeFlags . Instantiable ; return newInstance ; } export function cloneForScopeId ( type , scopeId , scopeName , scopeType ) { const newInstance = { ... type } ; newInstance . nameWithScope = makeNameWithScope ( type . details . name , scopeId ) ; newInstance . scopeId = scopeId ; newInstance . scopeName = scopeName ; newInstance . scopeType = scopeType ; return newInstance ; } export function cloneForUnpacked ( type , isInUnion = false ) { assert ( type . details . isVariadic ) ; const newInstance = { ... type } ; newInstance . isVariadicUnpacked = true ; newInstance . isVariadicInUnion = isInUnion ; return newInstance ; } export function cloneForPacked ( type ) { assert ( type . details . isVariadic ) ; const newInstance = { ... type } ; newInstance . isVariadicUnpacked = false ; newInstance . isVariadicInUnion = false ; return newInstance ; } export function cloneAsInvariant ( type ) { if ( type . details . isParamSpec || type . details . isVariadic ) { return type ; } if ( type . details . variance === Variance . Invariant ) { if ( type . details . boundType === undefined && type . details . constraints . length === 0 ) { return type ; } } const newInstance = { ... type } ; newInstance . details = { ... newInstance . details } ; newInstance . details . variance = Variance . Invariant ; newInstance . details . boundType = undefined ; newInstance . details . constraints = [ ] ; return newInstance ; } export function cloneForParamSpecAccess ( type , access ) { const newInstance = { ... type } ; newInstance . paramSpecAccess = access ; return newInstance ; } export function cloneAsSpecializedSelf ( type , specializedBoundType ) { assert ( type . details . isSynthesizedSelf ) ; const newInstance = { ... type } ; newInstance . details = { ... newInstance . details } ; newInstance . details . boundType = specializedBoundType ; return newInstance ; } export function makeNameWithScope ( name , scopeId ) { return `${ name }.${ scopeId }` ; } function create ( name , isParamSpec , typeFlags ) { const newTypeVarType = { category : TypeCategory . TypeVar , details : { name , constraints : [ ] , variance : Variance . Invariant , isParamSpec , isVariadic : false , isSynthesized : false , } , flags : typeFlags , } ; return newTypeVarType ; } export function addConstraint ( typeVarType , constraintType ) { typeVarType . details . constraints . push ( constraintType ) ; } export function getNameWithScope ( typeVarType ) { return typeVarType . nameWithScope || typeVarType . details . name ; } export function getReadableName ( typeVarType ) { if ( typeVarType . scopeName ) { return `${ typeVarType . details . name }@${ typeVarType . scopeName }` ; } return typeVarType . details . name ; } } export function isNever ( type ) { return type . category === TypeCategory . Never ; } export function isNoneInstance ( type ) { return type . category === TypeCategory . None && TypeBase . isInstance ( type ) ; } export function isNoneTypeClass ( type ) { return type . category === TypeCategory . None && TypeBase . isInstantiable ( type ) ; } export function isAny ( type ) { return type . category === TypeCategory . Any ; } export function isUnknown ( type ) { return type . category === TypeCategory . Unknown ; } export function isAnyOrUnknown ( type ) { if ( type . category === TypeCategory . Any || type . category === TypeCategory . Unknown ) { return true ; } if ( isUnion ( type ) ) { return type . subtypes . find ( ( subtype ) => ! isAnyOrUnknown ( subtype ) ) === undefined ; } return false ; } export function isUnbound ( type ) { return type . category === TypeCategory . Unbound ; } export function isUnion ( type ) { return type . category === TypeCategory . Union ; } export function isPossiblyUnbound ( type ) { if ( isUnbound ( type ) ) { return true ; } if ( isUnion ( type ) ) { return type . subtypes . find ( ( subtype ) => isPossiblyUnbound ( subtype ) ) !== undefined ; } return false ; } export function isClass ( type ) { return type . category === TypeCategory . Class ; } export function isInstantiableClass ( type ) { return type . category === TypeCategory . Class && TypeBase . isInstantiable ( type ) ; } export function isClassInstance ( type ) { return type . category === TypeCategory . Class && TypeBase . isInstance ( type ) ; } export function isModule ( type ) { return type . category === TypeCategory . Module ; } export function isTypeVar ( type ) { return type . category === TypeCategory . TypeVar ; } export function isVariadicTypeVar ( type ) { return type . category === TypeCategory . TypeVar && type . details . isVariadic ; } export function isUnpackedVariadicTypeVar ( type ) { if ( isUnion ( type ) && type . subtypes . length === 1 ) { type = type . subtypes [ 0 ] ; } return type . category === TypeCategory . TypeVar && type . details . isVariadic && ! ! type . isVariadicUnpacked ; } export function isParamSpec ( type ) { return type . category === TypeCategory . TypeVar && type . details . isParamSpec ; } export function isFunction ( type ) { return type . category === TypeCategory . Function ; } export function isOverloadedFunction ( type ) { return type . category === TypeCategory . OverloadedFunction ; } export function getTypeAliasInfo ( type ) { if ( type . typeAliasInfo ) { return type . typeAliasInfo ; } if ( isTypeVar ( type ) && type . details . recursiveTypeAliasName && type . details . boundType && type . details . boundType . typeAliasInfo ) { return type . details . boundType . typeAliasInfo ; } return undefined ; } export function isTypeSame ( type1 , type2 , ignorePseudoGeneric = false , ignoreTypeFlags = false , recursionCount = 0 ) { if ( type1 === type2 ) { return true ; } if ( type1 . category !== type2 . category ) { return false ; } if ( recursionCount > maxTypeRecursionCount ) { return true ; } if ( ! ignoreTypeFlags && type1 . flags !== type2 . flags ) { return false ; } switch ( type1 . category ) { case TypeCategory . Class : { const classType2 = type2 as ClassType ; if ( ! ClassType . isSameGenericClass ( type1 , classType2 , recursionCount + 1 ) ) { return false ; } if ( ! TypeCondition . isSame ( type1 . condition , type2 . condition ) ) { return false ; } if ( ! ignorePseudoGeneric || ! ClassType . isPseudoGenericClass ( type1 ) ) { if ( type1 . tupleTypeArguments && classType2 . tupleTypeArguments ) { const type1TupleTypeArgs = type1 . tupleTypeArguments || [ ] ; const type2TupleTypeArgs = classType2 . tupleTypeArguments || [ ] ; if ( type1TupleTypeArgs . length !== type2TupleTypeArgs . length ) { return false ; } for ( let i = 0 ; i < type1TupleTypeArgs . length ; i ++ ) { if ( ! isTypeSame ( type1TupleTypeArgs [ i ] , type2TupleTypeArgs [ i ] , ignorePseudoGeneric , false , recursionCount + 1 ) ) { return false ; } } } else { const type1TypeArgs = type1 . typeArguments || [ ] ; const type2TypeArgs = classType2 . typeArguments || [ ] ; const typeArgCount = Math . max ( type1TypeArgs . length , type2TypeArgs . length ) ; for ( let i = 0 ; i < typeArgCount ; i ++ ) { const typeArg1 = i < type1TypeArgs . length ? type1TypeArgs [ i ] : AnyType . create ( ) ; const typeArg2 = i < type2TypeArgs . length ? type2TypeArgs [ i ] : AnyType . create ( ) ; if ( ! isTypeSame ( typeArg1 , typeArg2 , ignorePseudoGeneric , false , recursionCount + 1 ) ) { return false ; } } } } if ( ! ClassType . isLiteralValueSame ( type1 , classType2 ) ) { return false ; } return true ; } case TypeCategory . Function : { const functionType2 = type2 as FunctionType ; const params1 = type1 . details . parameters ; const params2 = functionType2 . details . parameters ; if ( params1 . length !== params2 . length ) { return false ; } const positionalOnlyIndex1 = params1 . findIndex ( ( param ) => param . category === ParameterCategory . Simple && ! param . name ) ; const positionalOnlyIndex2 = params2 . findIndex ( ( param ) => param . category === ParameterCategory . Simple && ! param . name ) ; for ( let i = 0 ; i < params1 . length ; i ++ ) { const param1 = params1 [ i ] ; const param2 = params2 [ i ] ; if ( param1 . category !== param2 . category ) { return false ; } const isName1Relevant = positionalOnlyIndex1 !== undefined && i >= positionalOnlyIndex1 ; const isName2Relevant = positionalOnlyIndex2 !== undefined && i >= positionalOnlyIndex2 ; if ( isName1Relevant !== isName2Relevant ) { return false ; } if ( isName1Relevant ) { if ( param1 . name !== param2 . name ) { return false ; } } const param1Type = FunctionType . getEffectiveParameterType ( type1 , i ) ; const param2Type = FunctionType . getEffectiveParameterType ( functionType2 , i ) ; if ( ! isTypeSame ( param1Type , param2Type , ignorePseudoGeneric , false , recursionCount + 1 ) ) { return false ; } } let return1Type = type1 . details . declaredReturnType ; if ( type1 . specializedTypes && type1 . specializedTypes . returnType ) { return1Type = type1 . specializedTypes . returnType ; } if ( ! return1Type && type1 . inferredReturnType ) { return1Type = type1 . inferredReturnType ; } let return2Type = functionType2 . details . declaredReturnType ; if ( functionType2 . specializedTypes && functionType2 . specializedTypes . returnType ) { return2Type = functionType2 . specializedTypes . returnType ; } if ( ! return2Type && functionType2 . inferredReturnType ) { return2Type = functionType2 . inferredReturnType ; } if ( return1Type || return2Type ) { if ( ! return1Type || ! return2Type || ! isTypeSame ( return1Type , return2Type , ignorePseudoGeneric , false , recursionCount + 1 ) ) { return false ; } } return true ; } case TypeCategory . OverloadedFunction : { const functionType2 = type2 as OverloadedFunctionType ; if ( type1 . overloads . length !== functionType2 . overloads . length ) { return false ; } for ( let i = 0 ; i < type1 . overloads . length ; i ++ ) { if ( ! isTypeSame ( type1 . overloads [ i ] , functionType2 . overloads [ i ] , ignorePseudoGeneric , ignoreTypeFlags , recursionCount + 1 ) ) { return false ; } } return true ; } case TypeCategory . Union : { const unionType2 = type2 as UnionType ; const subtypes1 = type1 . subtypes ; const subtypes2 = unionType2 . subtypes ; if ( subtypes1 . length !== subtypes2 . length ) { return false ; } return ( findSubtype ( type1 , ( subtype ) => ! UnionType . containsType ( unionType2 , subtype , recursionCount + 1 ) ) === undefined ) ; } case TypeCategory . TypeVar : { const type2TypeVar = type2 as TypeVarType ; if ( type1 . scopeId !== type2TypeVar . scopeId ) { return false ; } const type1TypeArgs = type1 ?. typeAliasInfo ?. typeArguments || [ ] ; const type2TypeArgs = type2 ?. typeAliasInfo ?. typeArguments || [ ] ; const typeArgCount = Math . max ( type1TypeArgs . length , type2TypeArgs . length ) ; for ( let i = 0 ; i < typeArgCount ; i ++ ) { const typeArg1 = i < type1TypeArgs . length ? type1TypeArgs [ i ] : AnyType . create ( ) ; const typeArg2 = i < type2TypeArgs . length ? type2TypeArgs [ i ] : AnyType . create ( ) ; if ( ! isTypeSame ( typeArg1 , typeArg2 , ignorePseudoGeneric , false , recursionCount + 1 ) ) { return false ; } } if ( type1 . details === type2TypeVar . details ) { return true ; } if ( type1 . details . name !== type2TypeVar . details . name || type1 . details . isParamSpec !== type2TypeVar . details . isParamSpec || type1 . details . isVariadic !== type2TypeVar . details . isVariadic || type1 . details . isSynthesized !== type2TypeVar . details . isSynthesized || type1 . details . variance !== type2TypeVar . details . variance ) { return false ; } const boundType1 = type1 . details . boundType ; const boundType2 = type2TypeVar . details . boundType ; if ( boundType1 ) { if ( ! boundType2 || ! isTypeSame ( boundType1 , boundType2 , ignorePseudoGeneric , false , recursionCount + 1 ) ) { return false ; } } else { if ( boundType2 ) { return false ; } } const constraints1 = type1 . details . constraints ; const constraints2 = type2TypeVar . details . constraints ; if ( constraints1 . length !== constraints2 . length ) { return false ; } for ( let i = 0 ; i < constraints1 . length ; i ++ ) { if ( ! isTypeSame ( constraints1 [ i ] , constraints2 [ i ] , ignorePseudoGeneric , false , recursionCount + 1 ) ) { return false ; } } return true ; } case TypeCategory . Module : { const type2Module = type2 as ModuleType ; if ( type1 . fields === type2Module . fields ) { return true ; } if ( type1 . fields . size === 0 && type2Module . fields . size === 0 ) { return true ; } return false ; } } return true ; } export function removeUnknownFromUnion ( type ) { return removeFromUnion ( type , ( t ) => isUnknown ( t ) ) ; } export function removeUnbound ( type ) { if ( isUnion ( type ) ) { return removeFromUnion ( type , ( t ) => isUnbound ( t ) ) ; } if ( isUnbound ( type ) ) { return UnknownType . create ( ) ; } return type ; } export function removeNoneFromUnion ( type ) { return removeFromUnion ( type , ( t ) => isNoneInstance ( t ) ) ; } export function removeFromUnion ( type , removeFilter ) { if ( isUnion ( type ) ) { const remainingTypes = type . subtypes . filter ( ( t ) => ! removeFilter ( t ) ) ; if ( remainingTypes . length < type . subtypes . length ) { const newType = combineTypes ( remainingTypes ) ; if ( isUnion ( newType ) ) { UnionType . addTypeAliasSource ( newType , type ) ; } return newType ; } } return type ; } export function findSubtype ( type , filter ) { if ( isUnion ( type ) ) { return type . subtypes . find ( ( subtype ) => { return filter ( subtype ) ; } ) ; } return filter ( type ) ? type : undefined ; } export function combineTypes ( subtypes , maxSubtypeCount ? ) { subtypes = subtypes . filter ( ( subtype ) => subtype . category !== TypeCategory . Never ) ; if ( subtypes . length === 0 ) { return NeverType . create ( ) ; } let allSubtypesAreSame = true ; for ( let index = 1 ; index < subtypes . length ; index ++ ) { if ( subtypes [ index ] !== subtypes [ 0 ] ) { allSubtypesAreSame = false ; break ; } } if ( allSubtypesAreSame ) { return subtypes [ 0 ] ; } let expandedTypes = [ ] ; const typeAliasSources = [ ] ; for ( const subtype of subtypes ) { if ( isUnion ( subtype ) ) { expandedTypes . push ( ... subtype . subtypes ) ; if ( subtype . typeAliasInfo ) { typeAliasSources . push ( subtype ) ; } else if ( subtype . typeAliasSources ) { typeAliasSources . push ( ... subtype . typeAliasSources ) ; } } else { expandedTypes . push ( subtype ) ; } } expandedTypes = expandedTypes . sort ( ( type1 , type2 ) => { if ( ( isClassInstance ( type1 ) && type1 . literalValue !== undefined ) || ( isInstantiableClass ( type1 ) && type1 . literalValue !== undefined ) ) { return 1 ; } else if ( ( isClassInstance ( type2 ) && type2 . literalValue !== undefined ) || ( isInstantiableClass ( type2 ) && type2 . literalValue !== undefined ) ) { return - 1 ; } if ( isClassInstance ( type1 ) && type1 . isEmptyContainer ) { return 1 ; } else if ( isClassInstance ( type2 ) && type2 . isEmptyContainer ) { return - 1 ; } return 0 ; } ) ; if ( expandedTypes . length === 0 ) { return UnknownType . create ( ) ; } const newUnionType = UnionType . create ( ) ; if ( typeAliasSources . length > 0 ) { newUnionType . typeAliasSources = new Set < UnionType > ( ) ; typeAliasSources . forEach ( ( source ) => { newUnionType . typeAliasSources ! . add ( source ) ; } ) ; } let hitMaxSubtypeCount = false ; expandedTypes . forEach ( ( subtype , index ) => { if ( index === 0 ) { UnionType . addType ( newUnionType , subtype as UnionableType ) ; } else { if ( maxSubtypeCount === undefined || newUnionType . subtypes . length < maxSubtypeCount ) { _addTypeIfUnique ( newUnionType , subtype as UnionableType ) ; } else { hitMaxSubtypeCount = true ; } } } ) ; if ( hitMaxSubtypeCount ) { return AnyType . create ( ) ; } if ( newUnionType . subtypes . length === 1 ) { return newUnionType . subtypes [ 0 ] ; } return newUnionType ; } export function isSameWithoutLiteralValue ( destType , srcType ) { if ( isTypeSame ( destType , srcType ) ) { return true ; } if ( isInstantiableClass ( srcType ) && srcType . literalValue !== undefined ) { srcType = ClassType . cloneWithLiteral ( srcType , undefined ) ; return isTypeSame ( destType , srcType ) ; } if ( isClassInstance ( srcType ) && srcType . literalValue !== undefined ) { srcType = ClassType . cloneWithLiteral ( srcType , undefined ) ; return isTypeSame ( destType , srcType ) ; } return false ; } function _addTypeIfUnique ( unionType , typeToAdd ) { if ( isClassInstance ( typeToAdd ) && typeToAdd . condition === undefined ) { if ( ClassType . isBuiltIn ( typeToAdd , 'str' ) && typeToAdd . literalValue !== undefined && unionType . literalStrMap !== undefined ) { if ( ! unionType . literalStrMap . has ( typeToAdd . literalValue as string ) ) { UnionType . addType ( unionType , typeToAdd ) ; } return ; } else if ( ClassType . isBuiltIn ( typeToAdd , 'int' ) && typeToAdd . literalValue !== undefined && unionType . literalIntMap !== undefined ) { if ( ! unionType . literalIntMap . has ( typeToAdd . literalValue as number ) ) { UnionType . addType ( unionType , typeToAdd ) ; } return ; } } for ( let i = 0 ; i < unionType . subtypes . length ; i ++ ) { const type = unionType . subtypes [ i ] ; if ( isTypeSame ( type , typeToAdd ) ) { return ; } if ( isClassInstance ( type ) && isClassInstance ( typeToAdd ) ) { if ( isSameWithoutLiteralValue ( type , typeToAdd ) ) { if ( type . literalValue === undefined ) { return ; } } if ( ClassType . isBuiltIn ( type , 'bool' ) && ! type . condition && ClassType . isBuiltIn ( typeToAdd , 'bool' ) && ! typeToAdd . condition ) { if ( typeToAdd . literalValue !== undefined && ! typeToAdd . literalValue === type . literalValue ) { unionType . subtypes [ i ] = ClassType . cloneWithLiteral ( type , undefined ) ; return ; } } } if ( isClassInstance ( typeToAdd ) && typeToAdd . isEmptyContainer ) { if ( isClassInstance ( type ) && ClassType . isSameGenericClass ( type , typeToAdd ) ) { return ; } } } UnionType . addType ( unionType , typeToAdd ) ; }