import { assert } from '../common/debug' ; import { ParameterCategory } from '../parser/parseNodes' ; import { DeclarationType } from './declaration' ; import { Symbol , SymbolFlags , SymbolTable } from './symbol' ; import { isDunderName } from './symbolNameUtils' ; import { isTypedDictMemberAccessedThroughIndex } from './symbolUtils' ; import { AnyType , ClassType , combineTypes , findSubtype , FunctionParameter , FunctionType , FunctionTypeFlags , isAny , isAnyOrUnknown , isClass , isClassInstance , isFunction , isInstantiableClass , isNever , isNoneInstance , isOverloadedFunction , isParamSpec , isTypeSame , isTypeVar , isUnbound , isUnion , isUnknown , isVariadicTypeVar , maxTypeRecursionCount , ModuleType , NeverType , NoneType , OverloadedFunctionType , ParamSpecEntry , ParamSpecValue , removeFromUnion , SpecializedFunctionTypes , Type , TypeBase , TypeCategory , TypeCondition , TypeFlags , TypeVarScopeId , TypeVarType , UnionType , UnknownType , } from './types' ; import { TypeVarMap } from './typeVarMap' ; export interface ClassMember { symbol : Symbol ; classType : ClassType | UnknownType ; isInstanceMember : boolean ; isClassVar : boolean ; isTypeDeclared : boolean ; } export const enum ClassMemberLookupFlags { Default = 0 , SkipOriginalClass = 1 << 0 , SkipBaseClasses = 1 << 1 , SkipObjectBaseClass = 1 << 2 , SkipInstanceVariables = 1 << 3 , DeclaredTypesOnly = 1 << 4 , SkipTypeBaseClass = 1 << 5 } export const enum ClassIteratorFlags { Default = 0 , SkipOriginalClass = 1 << 0 , SkipBaseClasses = 1 << 1 , SkipObjectBaseClass = 1 << 2 , SkipTypeBaseClass = 1 << 3 } export const enum CanAssignFlags { Default = 0 , EnforceInvariance = 1 << 0 , ReverseTypeVarMatching = 1 << 1 , AllowTypeVarNarrowing = 1 << 2 , SkipSolveTypeVars = 1 << 3 , OverloadOverlapCheck = 1 << 4 , SkipFunctionReturnTypeCheck = 1 << 5 , AllowBoolTypeGuard = 1 << 6 , RetainLiteralsForTypeVar = 1 << 7 , SkipSelfClsTypeCheck = 1 << 8 , IgnoreTypeVarScope = 1 << 9 } export enum ParameterSource { PositionOnly , PositionOrKeyword , KeywordOnly } export interface ParameterDetails { param : FunctionParameter ; index : number ; source : ParameterSource ; } export interface ParameterListDetails { variadicParamIndex ? : number ; argsIndex ? : number ; variadicArgsIndex ? : number ; kwargsIndex ? : number ; firstPositionOrKeywordIndex : number ; positionOnlyParamCount : number ; positionParamCount : number ; firstKeywordOnlyIndex ? : number ; params : ParameterDetails [ ] ; } export function getParameterListDetails ( type ) { const result = { firstPositionOrKeywordIndex : 0 , positionParamCount : 0 , positionOnlyParamCount : 0 , params : [ ] , } ; let positionOnlyIndex = type . details . parameters . findIndex ( ( p ) => p . category === ParameterCategory . Simple && ! p . name ) ; if ( positionOnlyIndex < 0 ) { for ( let i = 0 ; i < type . details . parameters . length ; i ++ ) { const p = type . details . parameters [ i ] ; if ( p . category !== ParameterCategory . Simple ) { break ; } if ( ! p . name ) { break ; } if ( isDunderName ( p . name ) || ! p . name . startsWith ( '__' ) ) { break ; } positionOnlyIndex = i + 1 ; } } if ( positionOnlyIndex >= 0 ) { result . firstPositionOrKeywordIndex = positionOnlyIndex ; } for ( let i = 0 ; i < positionOnlyIndex ; i ++ ) { if ( type . details . parameters [ i ] . hasDefault ) { break ; } result . positionOnlyParamCount ++ ; result . positionParamCount ++ ; } let sawKeywordOnlySeparator = false ; type . details . parameters . forEach ( ( param , index ) => { if ( param . category === ParameterCategory . VarArgList ) { if ( ! sawKeywordOnlySeparator ) { result . firstKeywordOnlyIndex = result . params . length ; sawKeywordOnlySeparator = true ; } if ( param . name && result . argsIndex === undefined ) { result . argsIndex = result . params . length ; if ( isVariadicTypeVar ( param . type ) ) { result . variadicArgsIndex = result . params . length ; } } } if ( param . category === ParameterCategory . VarArgDictionary ) { if ( result . kwargsIndex === undefined ) { result . kwargsIndex = result . params . length ; } } if ( param . category === ParameterCategory . Simple ) { if ( isVariadicTypeVar ( param . type ) ) { result . variadicParamIndex = index ; } else if ( param . name && ! sawKeywordOnlySeparator ) { result . positionParamCount ++ ; } } if ( param . name ) { result . params . push ( { param , index , source : sawKeywordOnlySeparator ? ParameterSource . KeywordOnly : positionOnlyIndex >= 0 && index < positionOnlyIndex ? ParameterSource . PositionOnly : ParameterSource . PositionOrKeyword , } ) ; } } ) ; return result ; } export function isOptionalType ( type ) { if ( isUnion ( type ) ) { return findSubtype ( type , ( subtype ) => isNoneInstance ( subtype ) ) !== undefined ; } return false ; } export function mapSubtypes ( type , callback ) { if ( isUnion ( type ) ) { const newSubtypes = [ ] ; let typeChanged = false ; type . subtypes . forEach ( ( subtype ) => { const transformedType = callback ( subtype ) ; if ( transformedType ) { if ( transformedType !== subtype ) { newSubtypes . push ( addConditionToType ( transformedType , getTypeCondition ( type ) ) ) ; typeChanged = true ; } else { newSubtypes . push ( subtype ) ; } } else { typeChanged = true ; } } ) ; if ( ! typeChanged ) { return type ; } const newType = combineTypes ( newSubtypes ) ; if ( newType . category === TypeCategory . Union ) { UnionType . addTypeAliasSource ( newType , type ) ; } return newType ; } const transformedSubtype = callback ( type ) ; if ( ! transformedSubtype ) { return NeverType . create ( ) ; } return transformedSubtype ; } export function doForEachSubtype ( type , callback ) { if ( isUnion ( type ) ) { type . subtypes . forEach ( ( subtype , index ) => { callback ( subtype , index ) ; } ) ; } else { callback ( type , 0 ) ; } } export function areTypesSame ( types , ignorePseudoGeneric ) { if ( types . length < 2 ) { return true ; } for ( let i = 1 ; i < types . length ; i ++ ) { if ( ! isTypeSame ( types [ 0 ] , types [ i ] , ignorePseudoGeneric ) ) { return false ; } } return true ; } export function isUnionableType ( subtypes ) { let typeFlags = TypeFlags . Instance | TypeFlags . Instantiable ; for ( const subtype of subtypes ) { typeFlags &= subtype . flags ; } return ( typeFlags & TypeFlags . Instantiable ) !== 0 && ( typeFlags & TypeFlags . Instance ) === 0 ; } export function derivesFromAnyOrUnknown ( type ) { let anyOrUnknown = false ; doForEachSubtype ( type , ( subtype ) => { if ( isAnyOrUnknown ( type ) ) { anyOrUnknown = true ; } else if ( isInstantiableClass ( subtype ) ) { if ( ClassType . hasUnknownBaseClass ( subtype ) ) { anyOrUnknown = true ; } } else if ( isClassInstance ( subtype ) ) { if ( ClassType . hasUnknownBaseClass ( subtype ) ) { anyOrUnknown = true ; } } } ) ; return anyOrUnknown ; } export function getFullNameOfType ( type ) { if ( type . typeAliasInfo ?. fullName ) { return type . typeAliasInfo . fullName ; } switch ( type . category ) { case TypeCategory . Any : case TypeCategory . Unknown : return 'typing.Any' ; case TypeCategory . None : return 'builtins.None' ; case TypeCategory . Class : return type . details . fullName ; case TypeCategory . Function : return type . details . fullName ; case TypeCategory . Module : return type . moduleName ; case TypeCategory . OverloadedFunction : return type . overloads [ 0 ] . details . fullName ; } return undefined ; } export function stripLiteralValue ( type ) { if ( isClass ( type ) ) { if ( type . literalValue !== undefined ) { type = ClassType . cloneWithLiteral ( type , undefined ) ; } return type ; } if ( isUnion ( type ) ) { return mapSubtypes ( type , ( subtype ) => { return stripLiteralValue ( subtype ) ; } ) ; } return type ; } export function addConditionToType ( type , condition ) { if ( ! condition ) { return type ; } switch ( type . category ) { case TypeCategory . Unbound : case TypeCategory . Unknown : case TypeCategory . Any : case TypeCategory . Never : case TypeCategory . Module : case TypeCategory . TypeVar : return type ; case TypeCategory . None : case TypeCategory . Function : return TypeBase . cloneForCondition ( type , TypeCondition . combine ( type . condition , condition ) ) ; case TypeCategory . OverloadedFunction : return OverloadedFunctionType . create ( type . overloads . map ( ( t ) => addConditionToType ( t , condition ) as FunctionType ) ) ; case TypeCategory . Class : return TypeBase . cloneForCondition ( type , TypeCondition . combine ( type . condition , condition ) ) ; case TypeCategory . Union : return combineTypes ( type . subtypes . map ( ( t ) => addConditionToType ( t , condition ) ) ) ; } } export function getTypeCondition ( type ) { switch ( type . category ) { case TypeCategory . Unbound : case TypeCategory . Unknown : case TypeCategory . Any : case TypeCategory . Never : case TypeCategory . Module : case TypeCategory . TypeVar : case TypeCategory . OverloadedFunction : case TypeCategory . Union : return undefined ; case TypeCategory . None : case TypeCategory . Class : case TypeCategory . Function : return type . condition ; } } export function isTypeAliasPlaceholder ( type ) { if ( ! isTypeVar ( type ) ) { return false ; } return ! ! type . details . recursiveTypeAliasName && ! type . details . boundType ; } export function isTypeAliasRecursive ( typeAliasPlaceholder , type ) { if ( type . category !== TypeCategory . Union ) { if ( type === typeAliasPlaceholder ) { return true ; } return ( isUnbound ( type ) && type . typeAliasInfo && type . typeAliasInfo . name === typeAliasPlaceholder . details . recursiveTypeAliasName ) ; } return findSubtype ( type , ( subtype ) => isTypeSame ( typeAliasPlaceholder , subtype ) ) !== undefined ; } export function transformPossibleRecursiveTypeAlias ( type ) ; export function transformPossibleRecursiveTypeAlias ( type ) ; export function transformPossibleRecursiveTypeAlias ( type ) { if ( type ) { if ( isTypeVar ( type ) && type . details . recursiveTypeAliasName && type . details . boundType ) { const unspecializedType = TypeBase . isInstance ( type ) ? convertToInstance ( type . details . boundType ) : type . details . boundType ; if ( ! type . typeAliasInfo ?. typeArguments || ! type . details . recursiveTypeParameters ) { return unspecializedType ; } const typeVarMap = buildTypeVarMap ( type . details . recursiveTypeParameters , type . typeAliasInfo . typeArguments , getTypeVarScopeId ( type ) ) ; return applySolvedTypeVars ( unspecializedType , typeVarMap ) ; } } return type ; } export function getTypeVarScopeId ( type ) { if ( isClass ( type ) ) { return type . details . typeVarScopeId ; } if ( isFunction ( type ) ) { return type . details . typeVarScopeId ; } if ( isTypeVar ( type ) ) { return type . scopeId ; } return undefined ; } export function getSpecializedTupleType ( type ) { let classType ; if ( isInstantiableClass ( type ) ) { classType = type ; } else if ( isClassInstance ( type ) ) { classType = ClassType . cloneAsInstantiable ( type ) ; } if ( ! classType ) { return undefined ; } const tupleClass = classType . details . mro . find ( ( mroClass ) => isInstantiableClass ( mroClass ) && isTupleClass ( mroClass ) ) ; if ( ! tupleClass || ! isInstantiableClass ( tupleClass ) ) { return undefined ; } if ( ClassType . isSameGenericClass ( classType , tupleClass ) ) { return classType ; } const typeVarMap = buildTypeVarMapFromSpecializedClass ( classType ) ; return applySolvedTypeVars ( tupleClass , typeVarMap ) as ClassType ; } export function isLiteralType ( type ) { return TypeBase . isInstance ( type ) && type . literalValue !== undefined ; } export function isLiteralTypeOrUnion ( type ) { if ( isClassInstance ( type ) ) { return type . literalValue !== undefined ; } if ( isUnion ( type ) ) { return ! findSubtype ( type , ( subtype ) => ! isClassInstance ( subtype ) || subtype . literalValue === undefined ) ; } return false ; } export function containsLiteralType ( type , includeTypeArgs = false , recursionCount = 0 ) { if ( recursionCount > maxTypeRecursionCount ) { return false ; } if ( isClassInstance ( type ) && isLiteralType ( type ) ) { return true ; } if ( includeTypeArgs && isClass ( type ) ) { const typeArgs = type . tupleTypeArguments || type . typeArguments ; if ( typeArgs ) { return typeArgs . some ( ( typeArg ) => containsLiteralType ( typeArg , includeTypeArgs , recursionCount + 1 ) ) ; } } if ( isUnion ( type ) ) { return type . subtypes . some ( ( subtype ) => containsLiteralType ( subtype , includeTypeArgs , recursionCount + 1 ) ) ; } return false ; } export function isEllipsisType ( type ) { return isAny ( type ) && type . isEllipsis ; } export function isNoReturnType ( type ) { return isClassInstance ( type ) && ClassType . isBuiltIn ( type , 'NoReturn' ) ; } export function removeNoReturnFromUnion ( type ) { return removeFromUnion ( type , ( subtype ) => isNoReturnType ( subtype ) ) ; } export function isProperty ( type ) { return isClassInstance ( type ) && ClassType . isPropertyClass ( type ) ; } export function isTupleClass ( type ) { return ClassType . isBuiltIn ( type , 'tuple' ) ; } export function isOpenEndedTupleClass ( type ) { return ( type . tupleTypeArguments && type . tupleTypeArguments . length === 2 && isEllipsisType ( type . tupleTypeArguments [ 1 ] ) ) ; } export function partiallySpecializeType ( type , contextClassType , selfClass ? ) { if ( ClassType . isUnspecialized ( contextClassType ) ) { return type ; } const typeVarMap = buildTypeVarMapFromSpecializedClass ( contextClassType , undefined ) ; if ( selfClass ) { populateTypeVarMapForSelfType ( typeVarMap , contextClassType , selfClass ) ; } return applySolvedTypeVars ( type , typeVarMap ) ; } export function populateTypeVarMapForSelfType ( typeVarMap , contextClassType , selfClass ) { const synthesizedSelfTypeVar = synthesizeTypeVarForSelfCls ( contextClassType , false ) ; typeVarMap . setTypeVarType ( synthesizedSelfTypeVar , convertToInstance ( selfClass ) ) ; } export function applySolvedTypeVars ( type , typeVarMap , unknownIfNotFound = false , useNarrowBoundOnly = false , eliminateUnsolvedInUnions = false ) { if ( typeVarMap . isEmpty ( ) && ! unknownIfNotFound && ! eliminateUnsolvedInUnions ) { return type ; } const transformer = new ApplySolvedTypeVarsTransformer ( typeVarMap , unknownIfNotFound , useNarrowBoundOnly , eliminateUnsolvedInUnions ) ; return transformer . apply ( type ) ; } export function transformExpectedTypeForConstructor ( expectedType , typeVarMap , liveTypeVarScopes ) { const isTypeVarLive = ( typeVar ) => liveTypeVarScopes . some ( ( scopeId ) => typeVar . scopeId === scopeId ) ; if ( isTypeVar ( expectedType ) ) { if ( isTypeVarLive ( expectedType ) ) { return expectedType ; } return undefined ; } const transformer = new ExpectedConstructorTypeTransformer ( typeVarMap , liveTypeVarScopes ) ; return transformer . apply ( expectedType ) ; } export function lookUpObjectMember ( objectType , memberName , flags = ClassMemberLookupFlags . Default ) { if ( isClassInstance ( objectType ) ) { return lookUpClassMember ( objectType , memberName , flags ) ; } return undefined ; } export function lookUpClassMember ( classType , memberName , flags = ClassMemberLookupFlags . Default ) { const memberItr = getClassMemberIterator ( classType , memberName , flags ) ; return memberItr . next ( ) ?. value ; } export function * getClassMemberIterator ( classType , memberName , flags = ClassMemberLookupFlags . Default ) { const declaredTypesOnly = ( flags & ClassMemberLookupFlags . DeclaredTypesOnly ) !== 0 ; if ( isClass ( classType ) ) { let classFlags = ClassIteratorFlags . Default ; if ( flags & ClassMemberLookupFlags . SkipOriginalClass ) { classFlags = classFlags | ClassIteratorFlags . SkipOriginalClass ; } if ( flags & ClassMemberLookupFlags . SkipBaseClasses ) { classFlags = classFlags | ClassIteratorFlags . SkipBaseClasses ; } if ( flags & ClassMemberLookupFlags . SkipObjectBaseClass ) { classFlags = classFlags | ClassIteratorFlags . SkipObjectBaseClass ; } if ( flags & ClassMemberLookupFlags . SkipTypeBaseClass ) { classFlags = classFlags | ClassIteratorFlags . SkipTypeBaseClass ; } const classItr = getClassIterator ( classType , classFlags ) ; for ( const [ mroClass , specializedMroClass ] of classItr ) { if ( ! isInstantiableClass ( mroClass ) ) { if ( ! declaredTypesOnly ) { const cm = { symbol : Symbol . createWithType ( SymbolFlags . None , UnknownType . create ( ) ) , isInstanceMember : false , isClassVar : true , classType : UnknownType . create ( ) , isTypeDeclared : false , } ; yield cm ; } continue ; } if ( ! isInstantiableClass ( specializedMroClass ) ) { continue ; } const memberFields = specializedMroClass . details . fields ; if ( ( flags & ClassMemberLookupFlags . SkipInstanceVariables ) === 0 ) { const symbol = memberFields . get ( memberName ) ; if ( symbol && symbol . isInstanceMember ( ) ) { const hasDeclaredType = symbol . hasTypedDeclarations ( ) ; if ( ! declaredTypesOnly || hasDeclaredType ) { const cm = { symbol , isInstanceMember : true , isClassVar : symbol . isClassVar ( ) , classType : specializedMroClass , isTypeDeclared : hasDeclaredType , } ; yield cm ; } } } const symbol = memberFields . get ( memberName ) ; if ( symbol && symbol . isClassMember ( ) ) { const hasDeclaredType = symbol . hasTypedDeclarations ( ) ; if ( ! declaredTypesOnly || hasDeclaredType ) { let isInstanceMember = false ; if ( ClassType . isDataClass ( specializedMroClass ) || ClassType . isTypedDictClass ( specializedMroClass ) ) { const decls = symbol . getDeclarations ( ) ; if ( decls . length > 0 && decls [ 0 ] . type === DeclarationType . Variable ) { isInstanceMember = true ; } } const cm = { symbol , isInstanceMember , isClassVar : symbol . isClassVar ( ) , classType : specializedMroClass , isTypeDeclared : hasDeclaredType , } ; yield cm ; } } } } else if ( isAnyOrUnknown ( classType ) ) { const cm = { symbol : Symbol . createWithType ( SymbolFlags . None , UnknownType . create ( ) ) , isInstanceMember : false , isClassVar : true , classType : UnknownType . create ( ) , isTypeDeclared : false , } ; yield cm ; } return undefined ; } export function * getClassIterator ( classType , flags = ClassIteratorFlags . Default ) { if ( isClass ( classType ) ) { let skipMroEntry = ( flags & ClassIteratorFlags . SkipOriginalClass ) !== 0 ; for ( const mroClass of classType . details . mro ) { if ( skipMroEntry ) { skipMroEntry = false ; continue ; } const specializedMroClass = partiallySpecializeType ( mroClass , classType ) ; if ( flags & ClassIteratorFlags . SkipObjectBaseClass ) { if ( isInstantiableClass ( specializedMroClass ) ) { if ( ClassType . isBuiltIn ( specializedMroClass , 'object' ) ) { break ; } } } if ( flags & ClassIteratorFlags . SkipTypeBaseClass ) { if ( isInstantiableClass ( specializedMroClass ) ) { if ( ClassType . isBuiltIn ( specializedMroClass , 'type' ) ) { break ; } } } yield [ mroClass , specializedMroClass ] ; if ( ( flags & ClassIteratorFlags . SkipBaseClasses ) !== 0 ) { break ; } } } return undefined ; } export function getClassFieldsRecursive ( classType ) { const memberMap = new Map < string , ClassMember > ( ) ; for ( let i = classType . details . mro . length - 1 ; i >= 0 ; i -- ) { const mroClass = classType . details . mro [ i ] ; if ( ! isClass ( mroClass ) ) { memberMap . clear ( ) ; continue ; } mroClass . details . fields . forEach ( ( symbol , name ) => { if ( ! symbol . isIgnoredForProtocolMatch ( ) && symbol . hasTypedDeclarations ( ) ) { memberMap . set ( name , { classType : mroClass , symbol , isInstanceMember : symbol . isInstanceMember ( ) , isClassVar : symbol . isClassVar ( ) , isTypeDeclared : true , } ) ; } } ) ; } return memberMap ; } export function addTypeVarsToListIfUnique ( list1 , list2 ) { for ( const type2 of list2 ) { if ( ! list1 . find ( ( type1 ) => isTypeSame ( convertToInstance ( type1 ) , convertToInstance ( type2 ) ) ) ) { list1 . push ( type2 ) ; } } } export function getTypeVarArgumentsRecursive ( type , recursionCount = 0 ) { if ( recursionCount > maxTypeRecursionCount ) { return [ ] ; } const getTypeVarsFromClass = ( classType ) => { const combinedList = [ ] ; if ( classType . typeArguments ) { classType . typeArguments . forEach ( ( typeArg ) => { addTypeVarsToListIfUnique ( combinedList , getTypeVarArgumentsRecursive ( typeArg , recursionCount + 1 ) ) ; } ) ; } return combinedList ; } ; if ( type . typeAliasInfo ?. typeArguments ) { const combinedList = [ ] ; type . typeAliasInfo ?. typeArguments . forEach ( ( typeArg ) => { addTypeVarsToListIfUnique ( combinedList , getTypeVarArgumentsRecursive ( typeArg , recursionCount + 1 ) ) ; } ) ; return combinedList ; } if ( isTypeVar ( type ) ) { if ( type . details . recursiveTypeAliasName ) { return [ ] ; } if ( isParamSpec ( type ) && type . paramSpecAccess ) { return [ ] ; } return [ TypeBase . isInstantiable ( type ) ? TypeVarType . cloneAsInstance ( type ) : type ] ; } if ( isClass ( type ) ) { return getTypeVarsFromClass ( type ) ; } if ( isUnion ( type ) ) { const combinedList = [ ] ; doForEachSubtype ( type , ( subtype ) => { addTypeVarsToListIfUnique ( combinedList , getTypeVarArgumentsRecursive ( subtype , recursionCount + 1 ) ) ; } ) ; return combinedList ; } if ( isFunction ( type ) ) { const combinedList = [ ] ; for ( let i = 0 ; i < type . details . parameters . length ; i ++ ) { addTypeVarsToListIfUnique ( combinedList , getTypeVarArgumentsRecursive ( FunctionType . getEffectiveParameterType ( type , i ) , recursionCount + 1 ) ) ; } if ( type . details . paramSpec ) { addTypeVarsToListIfUnique ( combinedList , [ type . details . paramSpec ] ) ; } const returnType = FunctionType . getSpecializedReturnType ( type ) ; if ( returnType ) { addTypeVarsToListIfUnique ( combinedList , getTypeVarArgumentsRecursive ( returnType , recursionCount + 1 ) ) ; } return combinedList ; } return [ ] ; } export function specializeClassType ( type ) { const typeVarMap = new TypeVarMap ( getTypeVarScopeId ( type ) ) ; const typeParams = ClassType . getTypeParameters ( type ) ; typeParams . forEach ( ( typeParam ) => { typeVarMap . setTypeVarType ( typeParam , UnknownType . create ( ) ) ; } ) ; return applySolvedTypeVars ( type , typeVarMap ) as ClassType ; } export function setTypeArgumentsRecursive ( destType , srcType , typeVarMap , recursionCount = 0 ) { if ( recursionCount > maxTypeRecursionCount ) { return ; } if ( typeVarMap . isLocked ( ) ) { return ; } switch ( destType . category ) { case TypeCategory . Union : doForEachSubtype ( destType , ( subtype ) => { setTypeArgumentsRecursive ( subtype , srcType , typeVarMap , recursionCount + 1 ) ; } ) ; break ; case TypeCategory . Class : if ( destType . typeArguments ) { destType . typeArguments . forEach ( ( typeArg ) => { setTypeArgumentsRecursive ( typeArg , srcType , typeVarMap , recursionCount + 1 ) ; } ) ; } if ( destType . tupleTypeArguments ) { destType . tupleTypeArguments . forEach ( ( typeArg ) => { setTypeArgumentsRecursive ( typeArg , srcType , typeVarMap , recursionCount + 1 ) ; } ) ; } break ; case TypeCategory . Function : if ( destType . specializedTypes ) { destType . specializedTypes . parameterTypes . forEach ( ( paramType ) => { setTypeArgumentsRecursive ( paramType , srcType , typeVarMap , recursionCount + 1 ) ; } ) ; if ( destType . specializedTypes . returnType ) { setTypeArgumentsRecursive ( destType . specializedTypes . returnType , srcType , typeVarMap , recursionCount + 1 ) ; } } else { destType . details . parameters . forEach ( ( param ) => { setTypeArgumentsRecursive ( param . type , srcType , typeVarMap , recursionCount + 1 ) ; } ) ; if ( destType . details . declaredReturnType ) { setTypeArgumentsRecursive ( destType . details . declaredReturnType , srcType , typeVarMap , recursionCount + 1 ) ; } } break ; case TypeCategory . OverloadedFunction : destType . overloads . forEach ( ( subtype ) => { setTypeArgumentsRecursive ( subtype , srcType , typeVarMap , recursionCount + 1 ) ; } ) ; break ; case TypeCategory . TypeVar : if ( ! typeVarMap . hasTypeVar ( destType ) ) { typeVarMap . setTypeVarType ( destType , srcType ) ; } break ; } } export function buildTypeVarMapFromSpecializedClass ( classType , makeConcrete = true ) { const typeParameters = ClassType . getTypeParameters ( classType ) ; let typeArguments = classType . typeArguments ; if ( ! typeArguments && ! makeConcrete ) { typeArguments = typeParameters ; } const typeVarMap = buildTypeVarMap ( typeParameters , typeArguments , getTypeVarScopeId ( classType ) ) ; if ( ClassType . isTupleClass ( classType ) && classType . tupleTypeArguments && typeParameters . length >= 1 ) { typeVarMap . setVariadicTypeVar ( typeParameters [ 0 ] , classType . tupleTypeArguments ) ; } return typeVarMap ; } export function buildTypeVarMap ( typeParameters , typeArgs , typeVarScopeId ) { const typeVarMap = new TypeVarMap ( typeVarScopeId ) ; typeParameters . forEach ( ( typeParam , index ) => { let typeArgType ; if ( typeArgs ) { if ( isParamSpec ( typeParam ) ) { if ( index < typeArgs . length ) { typeArgType = typeArgs [ index ] ; if ( isFunction ( typeArgType ) && FunctionType . isParamSpecValue ( typeArgType ) ) { const paramSpecEntries = [ ] ; const typeArgFunctionType = typeArgType ; typeArgType . details . parameters . forEach ( ( param , paramIndex ) => { paramSpecEntries . push ( { category : param . category , name : param . name , hasDefault : ! ! param . hasDefault , isNameSynthesized : param . isNameSynthesized , type : FunctionType . getEffectiveParameterType ( typeArgFunctionType , paramIndex ) , } ) ; } ) ; typeVarMap . setParamSpec ( typeParam , { parameters : paramSpecEntries , flags : typeArgType . details . flags , docString : typeArgType . details . docString , paramSpec : typeArgType . details . paramSpec , } ) ; } else if ( isParamSpec ( typeArgType ) ) { typeVarMap . setParamSpec ( typeParam , { flags : FunctionTypeFlags . None , parameters : [ ] , docString : undefined , paramSpec : typeArgType , } ) ; } } } else { if ( index >= typeArgs . length ) { typeArgType = AnyType . create ( ) ; } else { typeArgType = typeArgs [ index ] ; } typeVarMap . setTypeVarType ( typeParam , typeArgType , typeArgType , true ) ; } } } ) ; return typeVarMap ; } export function specializeForBaseClass ( srcType , baseClass ) { const typeParams = ClassType . getTypeParameters ( baseClass ) ; if ( typeParams . length === 0 ) { return baseClass ; } const typeVarMap = buildTypeVarMapFromSpecializedClass ( srcType ) ; const specializedType = applySolvedTypeVars ( baseClass , typeVarMap ) ; assert ( isInstantiableClass ( specializedType ) ) ; return specializedType as ClassType ; } export function derivesFromClassRecursive ( classType , baseClassToFind , ignoreUnknown ) { if ( ClassType . isSameGenericClass ( classType , baseClassToFind ) ) { return true ; } for ( const baseClass of classType . details . baseClasses ) { if ( isInstantiableClass ( baseClass ) ) { if ( derivesFromClassRecursive ( baseClass , baseClassToFind , ignoreUnknown ) ) { return true ; } } else if ( ! ignoreUnknown && isAnyOrUnknown ( baseClass ) ) { return true ; } } return false ; } export function synthesizeTypeVarForSelfCls ( classType , isClsParam ) { const selfType = TypeVarType . createInstance ( `__type_of_self__` ) ; const scopeId = getTypeVarScopeId ( classType ) ?? '' ; selfType . details . isSynthesized = true ; selfType . details . isSynthesizedSelf = true ; selfType . nameWithScope = TypeVarType . makeNameWithScope ( selfType . details . name , scopeId ) ; selfType . scopeId = scopeId ; const boundType = ClassType . cloneForSpecialization ( classType , ClassType . getTypeParameters ( classType ) , false , true ) ; selfType . details . boundType = ClassType . cloneAsInstance ( boundType ) ; return isClsParam ? TypeVarType . cloneAsInstantiable ( selfType ) : selfType ; } export function getDeclaredGeneratorSendType ( functionType ) { const returnType = FunctionType . getSpecializedReturnType ( functionType ) ; if ( returnType ) { const generatorTypeArgs = getGeneratorTypeArgs ( returnType ) ; if ( generatorTypeArgs ) { return generatorTypeArgs . length >= 2 ? generatorTypeArgs [ 1 ] : UnknownType . create ( ) ; } } return undefined ; } export function getDeclaredGeneratorReturnType ( functionType ) { const returnType = FunctionType . getSpecializedReturnType ( functionType ) ; if ( returnType ) { const generatorTypeArgs = getGeneratorTypeArgs ( returnType ) ; if ( generatorTypeArgs ) { return generatorTypeArgs . length >= 3 ? generatorTypeArgs [ 2 ] : UnknownType . create ( ) ; } } return undefined ; } export function getGeneratorYieldType ( declaredReturnType , isAsync ) { let isLegalGeneratorType = true ; const yieldType = mapSubtypes ( declaredReturnType , ( subtype ) => { if ( isAnyOrUnknown ( subtype ) ) { return subtype ; } if ( isClassInstance ( subtype ) ) { const expectedClasses = [ [ 'AsyncIterable' , 'Iterable' ] , [ 'AsyncIterator' , 'Iterator' ] , [ 'AsyncGenerator' , 'Generator' ] , ] ; if ( expectedClasses . some ( ( classes ) => ClassType . isBuiltIn ( subtype , isAsync ? classes [ 0 ] : classes [ 1 ] ) ) ) { return subtype . typeArguments && subtype . typeArguments . length >= 1 ? subtype . typeArguments [ 0 ] : UnknownType . create ( ) ; } } isLegalGeneratorType = false ; return undefined ; } ) ; return isLegalGeneratorType ? yieldType : undefined ; } export function convertToInstance ( type ) { let result = mapSubtypes ( type , ( subtype ) => { switch ( subtype . category ) { case TypeCategory . Class : { if ( ClassType . isBuiltIn ( subtype , 'Type' ) ) { if ( ! subtype . typeArguments || subtype . typeArguments . length < 1 ) { return UnknownType . create ( ) ; } else { return convertToInstantiable ( subtype . typeArguments [ 0 ] ) ; } } return ClassType . cloneAsInstance ( subtype ) ; } case TypeCategory . None : { return NoneType . createInstance ( ) ; } case TypeCategory . Function : { if ( TypeBase . isInstantiable ( subtype ) ) { return FunctionType . cloneAsInstance ( subtype ) ; } break ; } case TypeCategory . TypeVar : { if ( TypeBase . isInstantiable ( subtype ) ) { return TypeVarType . cloneAsInstance ( subtype ) ; } break ; } } return subtype ; } ) ; if ( type . typeAliasInfo && type !== result ) { result = TypeBase . cloneForTypeAlias ( result , type . typeAliasInfo . name , type . typeAliasInfo . fullName , type . typeAliasInfo . typeVarScopeId , type . typeAliasInfo . typeParameters , type . typeAliasInfo . typeArguments ) ; } return result ; } export function convertToInstantiable ( type ) { let result = mapSubtypes ( type , ( subtype ) => { switch ( subtype . category ) { case TypeCategory . Class : { if ( TypeBase . isInstance ( subtype ) ) { return ClassType . cloneAsInstantiable ( subtype ) ; } break ; } case TypeCategory . None : { return NoneType . createType ( ) ; } case TypeCategory . Function : { if ( TypeBase . isInstance ( subtype ) ) { return FunctionType . cloneAsInstantiable ( subtype ) ; } break ; } case TypeCategory . TypeVar : { if ( TypeBase . isInstance ( subtype ) ) { return TypeVarType . cloneAsInstantiable ( subtype ) ; } break ; } } return subtype ; } ) ; if ( type . typeAliasInfo && type !== result ) { result = TypeBase . cloneForTypeAlias ( result , type . typeAliasInfo . name , type . typeAliasInfo . fullName , type . typeAliasInfo . typeVarScopeId , type . typeAliasInfo . typeParameters , type . typeAliasInfo . typeArguments ) ; } return result ; } export function getMembersForClass ( classType , symbolTable , includeInstanceVars ) { for ( let i = 0 ; i < classType . details . mro . length ; i ++ ) { const mroClass = classType . details . mro [ i ] ; if ( isInstantiableClass ( mroClass ) ) { const isClassTypedDict = ClassType . isTypedDictClass ( mroClass ) ; mroClass . details . fields . forEach ( ( symbol , name ) => { if ( symbol . isClassMember ( ) || ( includeInstanceVars && symbol . isInstanceMember ( ) ) ) { if ( ! isClassTypedDict || ! isTypedDictMemberAccessedThroughIndex ( symbol ) ) { if ( ! symbol . isInitVar ( ) ) { if ( ! symbolTable . get ( name ) ) { symbolTable . set ( name , symbol ) ; } } } } } ) ; } } if ( ! includeInstanceVars ) { const metaclass = classType . details . effectiveMetaclass ; if ( metaclass && isInstantiableClass ( metaclass ) ) { for ( const mroClass of metaclass . details . mro ) { if ( isInstantiableClass ( mroClass ) ) { mroClass . details . fields . forEach ( ( symbol , name ) => { if ( ! symbolTable . get ( name ) ) { symbolTable . set ( name , symbol ) ; } } ) ; } else { break ; } } } } } export function getMembersForModule ( moduleType , symbolTable ) { if ( moduleType . loaderFields ) { moduleType . loaderFields . forEach ( ( symbol , name ) => { symbolTable . set ( name , symbol ) ; } ) ; } moduleType . fields . forEach ( ( symbol , name ) => { symbolTable . set ( name , symbol ) ; } ) ; } export function containsUnknown ( type ) { let foundUnknown = false ; doForEachSubtype ( type , ( subtype ) => { if ( isUnknown ( subtype ) ) { foundUnknown = true ; } } ) ; return foundUnknown ; } export function isPartlyUnknown ( type , allowUnknownTypeArgsForClasses = false , recursionCount = 0 ) { if ( recursionCount > maxTypeRecursionCount ) { return false ; } if ( isUnknown ( type ) ) { return true ; } if ( type . typeAliasInfo ?. typeArguments ) { if ( type . typeAliasInfo . typeArguments . some ( ( typeArg ) => isPartlyUnknown ( typeArg , allowUnknownTypeArgsForClasses , recursionCount + 1 ) ) ) { return true ; } } if ( isUnion ( type ) ) { return ( findSubtype ( type , ( subtype ) => isPartlyUnknown ( subtype , allowUnknownTypeArgsForClasses , recursionCount + 1 ) ) !== undefined ) ; } if ( isClass ( type ) ) { if ( TypeBase . isInstance ( type ) ) { allowUnknownTypeArgsForClasses = false ; } if ( ! allowUnknownTypeArgsForClasses && ! ClassType . isPseudoGenericClass ( type ) ) { const typeArgs = type . tupleTypeArguments || type . typeArguments ; if ( typeArgs ) { for ( const argType of typeArgs ) { if ( isPartlyUnknown ( argType , allowUnknownTypeArgsForClasses , recursionCount + 1 ) ) { return true ; } } } } return false ; } if ( isOverloadedFunction ( type ) ) { return type . overloads . some ( ( overload ) => { return isPartlyUnknown ( overload , false , recursionCount + 1 ) ; } ) ; } if ( isFunction ( type ) ) { for ( let i = 0 ; i < type . details . parameters . length ; i ++ ) { if ( type . details . parameters [ i ] . name ) { const paramType = FunctionType . getEffectiveParameterType ( type , i ) ; if ( isPartlyUnknown ( paramType , false , recursionCount + 1 ) ) { return true ; } } } if ( type . details . declaredReturnType && ! FunctionType . isParamSpecValue ( type ) && isPartlyUnknown ( type . details . declaredReturnType , false , recursionCount + 1 ) ) { return true ; } return false ; } return false ; } export function explodeGenericClass ( classType ) { if ( ! classType . typeArguments || classType . typeArguments . length !== 1 || ! isUnion ( classType . typeArguments [ 0 ] ) ) { return classType ; } return combineTypes ( classType . typeArguments [ 0 ] . subtypes . map ( ( subtype ) => { return ClassType . cloneForSpecialization ( classType , [ subtype ] , true ) ; } ) ) ; } export function combineSameSizedTuples ( type , tupleType ) { if ( ! tupleType || ! isInstantiableClass ( tupleType ) ) { return undefined ; } let tupleEntries ; let isValid = true ; doForEachSubtype ( type , ( subtype ) => { if ( isClassInstance ( subtype ) ) { let tupleClass ; if ( isClass ( subtype ) && isTupleClass ( subtype ) && ! isOpenEndedTupleClass ( subtype ) ) { tupleClass = subtype ; } if ( ! tupleClass ) { tupleClass = subtype . details . mro . find ( ( mroClass ) => isClass ( mroClass ) && isTupleClass ( mroClass ) && ! isOpenEndedTupleClass ( mroClass ) ) as ClassType | undefined ; } if ( tupleClass && isClass ( tupleClass ) && tupleClass . tupleTypeArguments ) { if ( tupleEntries ) { if ( tupleEntries . length === tupleClass . tupleTypeArguments . length ) { tupleClass . tupleTypeArguments . forEach ( ( entry , index ) => { tupleEntries ! [ index ] . push ( entry ) ; } ) ; } else { isValid = false ; } } else { tupleEntries = tupleClass . tupleTypeArguments . map ( ( entry ) => [ entry ] ) ; } } else { isValid = false ; } } else { isValid = false ; } } ) ; if ( ! isValid || ! tupleEntries ) { return undefined ; } return convertToInstance ( specializeTupleClass ( tupleType , tupleEntries . map ( ( entry ) => combineTypes ( entry ) ) ) ) ; } export function specializeTupleClass ( classType , typeArgs , isTypeArgumentExplicit = true , stripLiterals = true , isForUnpackedVariadicTypeVar = false ) { let combinedTupleType = AnyType . create ( false ) ; if ( typeArgs . length === 2 && isEllipsisType ( typeArgs [ 1 ] ) ) { combinedTupleType = typeArgs [ 0 ] ; } else { combinedTupleType = combineTypes ( typeArgs ) ; } if ( stripLiterals ) { combinedTupleType = stripLiteralValue ( combinedTupleType ) ; } if ( isNever ( combinedTupleType ) ) { combinedTupleType = AnyType . create ( ) ; } const clonedClassType = ClassType . cloneForSpecialization ( classType , [ combinedTupleType ] , isTypeArgumentExplicit , undefined , typeArgs ) ; if ( isForUnpackedVariadicTypeVar ) { clonedClassType . isTupleForUnpackedVariadicTypeVar = true ; } return clonedClassType ; } export function removeParamSpecVariadicsFromSignature ( type ) { if ( isFunction ( type ) ) { return removeParamSpecVariadicsFromFunction ( type ) ; } const newOverloads = [ ] ; let newTypeNeeded = false ; for ( const overload of type . overloads ) { const newOverload = removeParamSpecVariadicsFromFunction ( overload ) ; newOverloads . push ( newOverload ) ; if ( newOverload !== overload ) { newTypeNeeded = true ; } } return newTypeNeeded ? OverloadedFunctionType . create ( newOverloads ) : type ; } export function removeParamSpecVariadicsFromFunction ( type ) { const paramCount = type . details . parameters . length ; if ( paramCount < 2 ) { return type ; } const argsParam = type . details . parameters [ paramCount - 2 ] ; const kwargsParam = type . details . parameters [ paramCount - 1 ] ; if ( argsParam . category !== ParameterCategory . VarArgList || kwargsParam . category !== ParameterCategory . VarArgDictionary || ! isParamSpec ( argsParam . type ) || ! isParamSpec ( kwargsParam . type ) || ! isTypeSame ( argsParam . type , kwargsParam . type ) ) { return type ; } return FunctionType . cloneRemoveParamSpecVariadics ( type , argsParam . type ) ; } function _expandVariadicUnpackedUnion ( type ) { if ( isClassInstance ( type ) && isTupleClass ( type ) && type . tupleTypeArguments && type . isTupleForUnpackedVariadicTypeVar ) { return combineTypes ( type . tupleTypeArguments ) ; } return type ; } export function getGeneratorTypeArgs ( returnType ) { if ( isClassInstance ( returnType ) ) { if ( ClassType . isBuiltIn ( returnType ) ) { const className = returnType . details . name ; if ( className === 'Generator' || className === 'AsyncGenerator' ) { return returnType . typeArguments ; } } } return undefined ; } export function requiresTypeArguments ( classType ) { if ( classType . details . typeParameters . length > 0 ) { return ! classType . details . typeParameters [ 0 ] . details . isSynthesized ; } if ( ClassType . isSpecialBuiltIn ( classType ) ) { const specialClasses = [ 'Tuple' , 'Callable' , 'Generic' , 'Type' , 'Optional' , 'Union' , 'Literal' , 'Annotated' , 'TypeGuard' , ] ; if ( specialClasses . some ( ( t ) => t === ( classType . aliasName || classType . details . name ) ) ) { return true ; } } return false ; } export function requiresSpecialization ( type , ignorePseudoGeneric = false , recursionCount = 0 ) { switch ( type . category ) { case TypeCategory . Class : { if ( ClassType . isPseudoGenericClass ( type ) && ignorePseudoGeneric ) { return false ; } if ( type . typeArguments ) { if ( recursionCount > maxTypeRecursionCount ) { return false ; } return ( type . typeArguments . find ( ( typeArg ) => requiresSpecialization ( typeArg , ignorePseudoGeneric , recursionCount + 1 ) ) !== undefined ) ; } return ClassType . getTypeParameters ( type ) . length > 0 ; } case TypeCategory . Function : { if ( recursionCount > maxTypeRecursionCount ) { return false ; } if ( type . details . paramSpec ) { return true ; } for ( let i = 0 ; i < type . details . parameters . length ; i ++ ) { if ( requiresSpecialization ( FunctionType . getEffectiveParameterType ( type , i ) , ignorePseudoGeneric , recursionCount + 1 ) ) { return true ; } } const declaredReturnType = type . specializedTypes && type . specializedTypes . returnType ? type . specializedTypes . returnType : type . details . declaredReturnType ; if ( declaredReturnType ) { if ( requiresSpecialization ( declaredReturnType , ignorePseudoGeneric , recursionCount + 1 ) ) { return true ; } } else if ( type . inferredReturnType ) { if ( requiresSpecialization ( type . inferredReturnType , ignorePseudoGeneric , recursionCount + 1 ) ) { return true ; } } return false ; } case TypeCategory . OverloadedFunction : { return ( type . overloads . find ( ( overload ) => requiresSpecialization ( overload , ignorePseudoGeneric , recursionCount + 1 ) ) !== undefined ) ; } case TypeCategory . Union : { return ( findSubtype ( type , ( subtype ) => requiresSpecialization ( subtype , ignorePseudoGeneric , recursionCount + 1 ) ) !== undefined ) ; } case TypeCategory . TypeVar : { if ( ! type . details . recursiveTypeAliasName ) { return true ; } if ( type . typeAliasInfo ?. typeArguments ) { return type . typeAliasInfo . typeArguments . some ( ( typeArg ) => requiresSpecialization ( typeArg , ignorePseudoGeneric , recursionCount + 1 ) ) ; } } } return false ; } export function computeMroLinearization ( classType ) { let isMroFound = true ; const classListsToMerge = [ ] ; const baseClassesToInclude = classType . details . baseClasses . filter ( ( baseClass ) => ! isInstantiableClass ( baseClass ) || ! ClassType . isBuiltIn ( baseClass , 'Generic' ) ) ; baseClassesToInclude . forEach ( ( baseClass ) => { if ( isInstantiableClass ( baseClass ) ) { const typeVarMap = buildTypeVarMapFromSpecializedClass ( baseClass , false ) ; classListsToMerge . push ( baseClass . details . mro . map ( ( mroClass ) => { return applySolvedTypeVars ( mroClass , typeVarMap ) ; } ) ) ; } else { classListsToMerge . push ( [ baseClass ] ) ; } } ) ; classListsToMerge . push ( baseClassesToInclude . map ( ( baseClass ) => { const typeVarMap = buildTypeVarMapFromSpecializedClass ( classType , false ) ; return applySolvedTypeVars ( baseClass , typeVarMap ) ; } ) ) ; const typeVarMap = buildTypeVarMapFromSpecializedClass ( classType , false ) ; classType . details . mro . push ( applySolvedTypeVars ( classType , typeVarMap ) ) ; const isInTail = ( searchClass , classLists ) => { return classLists . some ( ( classList ) => { return ( classList . findIndex ( ( value ) => isInstantiableClass ( value ) && ClassType . isSameGenericClass ( value , searchClass ) ) > 0 ) ; } ) ; } ; const filterClass = ( classToFilter , classLists ) => { for ( let i = 0 ; i < classLists . length ; i ++ ) { classLists [ i ] = classLists [ i ] . filter ( ( value ) => ! isInstantiableClass ( value ) || ! ClassType . isSameGenericClass ( value , classToFilter ) ) ; } } ; while ( true ) { let foundValidHead = false ; let nonEmptyList = undefined ; for ( let i = 0 ; i < classListsToMerge . length ; i ++ ) { const classList = classListsToMerge [ i ] ; if ( classList . length > 0 ) { if ( nonEmptyList === undefined ) { nonEmptyList = classList ; } if ( ! isInstantiableClass ( classList [ 0 ] ) ) { foundValidHead = true ; classType . details . mro . push ( classList [ 0 ] ) ; classList . shift ( ) ; break ; } else if ( ! isInTail ( classList [ 0 ] , classListsToMerge ) ) { foundValidHead = true ; classType . details . mro . push ( classList [ 0 ] ) ; filterClass ( classList [ 0 ] , classListsToMerge ) ; break ; } } } if ( ! nonEmptyList ) { break ; } if ( ! foundValidHead ) { isMroFound = false ; if ( ! isInstantiableClass ( nonEmptyList [ 0 ] ) ) { classType . details . mro . push ( nonEmptyList [ 0 ] ) ; nonEmptyList . shift ( ) ; } else { classType . details . mro . push ( nonEmptyList [ 0 ] ) ; filterClass ( nonEmptyList [ 0 ] , classListsToMerge ) ; } } } return isMroFound ; } export function getDeclaringModulesForType ( type ) { const moduleList = [ ] ; addDeclaringModuleNamesForType ( type , moduleList ) ; return moduleList ; } function addDeclaringModuleNamesForType ( type , moduleList , recursionCount = 0 ) { if ( recursionCount > maxTypeRecursionCount ) { return ; } const addIfUnique = ( moduleName ) => { if ( moduleName && ! moduleList . some ( ( n ) => n === moduleName ) ) { moduleList . push ( moduleName ) ; } } ; switch ( type . category ) { case TypeCategory . Class : { addIfUnique ( type . details . moduleName ) ; break ; } case TypeCategory . Function : { addIfUnique ( type . details . moduleName ) ; break ; } case TypeCategory . OverloadedFunction : { type . overloads . forEach ( ( overload ) => { addDeclaringModuleNamesForType ( overload , moduleList , recursionCount + 1 ) ; } ) ; break ; } case TypeCategory . Union : { doForEachSubtype ( type , ( subtype ) => { addDeclaringModuleNamesForType ( subtype , moduleList , recursionCount + 1 ) ; } ) ; break ; } case TypeCategory . Module : { addIfUnique ( type . moduleName ) ; break ; } } } export function convertParamSpecValueToType ( paramSpecEntry ) { if ( paramSpecEntry . parameters . length > 0 || ! paramSpecEntry . paramSpec ) { const functionType = FunctionType . createInstance ( '' , '' , '' , FunctionTypeFlags . ParamSpecValue ) ; paramSpecEntry . parameters . forEach ( ( entry ) => { FunctionType . addParameter ( functionType , { category : entry . category , name : entry . name , hasDefault : entry . hasDefault , isNameSynthesized : entry . isNameSynthesized , hasDeclaredType : true , type : entry . type , } ) ; } ) ; functionType . details . paramSpec = paramSpecEntry . paramSpec ; functionType . details . docString = paramSpecEntry . docString ; return functionType ; } return paramSpecEntry . paramSpec ; } class TypeVarTransformer { private _isTransformingTypeArg = false ; apply ( type , recursionSet = new Set < string > ( ) , recursionLevel = 0 ) { if ( recursionLevel > maxTypeRecursionCount ) { return type ; } if ( ! requiresSpecialization ( type ) ) { return type ; } if ( isAnyOrUnknown ( type ) ) { return type ; } if ( isNoneInstance ( type ) ) { return type ; } if ( isTypeVar ( type ) ) { if ( type . details . recursiveTypeAliasName ) { if ( ! type . typeAliasInfo ?. typeArguments ) { return type ; } let requiresUpdate = false ; const typeArgs = type . typeAliasInfo . typeArguments . map ( ( typeArg ) => { const replacementType = this . apply ( typeArg , recursionSet , recursionLevel + 1 ) ; if ( replacementType !== typeArg ) { requiresUpdate = true ; } return replacementType ; } ) ; if ( requiresUpdate ) { return TypeBase . cloneForTypeAlias ( type , type . typeAliasInfo . name , type . typeAliasInfo . fullName , type . typeAliasInfo . typeVarScopeId , type . typeAliasInfo . typeParameters , typeArgs ) ; } return type ; } let replacementType = type ; const typeVarName = TypeVarType . getNameWithScope ( type ) ; if ( ! recursionSet . has ( typeVarName ) ) { replacementType = this . transformTypeVar ( type ) ; if ( ! this . _isTransformingTypeArg ) { recursionSet . add ( typeVarName ) ; replacementType = this . apply ( replacementType , recursionSet , recursionLevel + 1 ) ; recursionSet . delete ( typeVarName ) ; } if ( isVariadicTypeVar ( type ) && type . isVariadicInUnion ) { replacementType = _expandVariadicUnpackedUnion ( replacementType ) ; } } return replacementType ; } if ( isUnion ( type ) ) { const newUnionType = mapSubtypes ( type , ( subtype ) => { let transformedType = this . apply ( subtype , recursionSet , recursionLevel + 1 ) ; if ( isVariadicTypeVar ( subtype ) && ! isVariadicTypeVar ( transformedType ) ) { const subtypesToCombine = [ ] ; doForEachSubtype ( transformedType , ( transformedSubtype ) => { subtypesToCombine . push ( _expandVariadicUnpackedUnion ( transformedSubtype ) ) ; } ) ; transformedType = combineTypes ( subtypesToCombine ) ; } return transformedType ; } ) ; if ( this . transformUnion && isUnion ( newUnionType ) ) { return this . transformUnion ( newUnionType ) ; } return newUnionType ; } if ( isClass ( type ) ) { return this . _transformTypeVarsInClassType ( type , recursionSet , recursionLevel + 1 ) ; } if ( isFunction ( type ) ) { return this . _transformTypeVarsInFunctionType ( type , recursionSet , recursionLevel + 1 ) ; } if ( isOverloadedFunction ( type ) ) { let requiresUpdate = false ; const newOverloads = [ ] ; type . overloads . forEach ( ( entry ) => { const replacementType = this . _transformTypeVarsInFunctionType ( entry , recursionSet , recursionLevel ) ; newOverloads . push ( replacementType ) ; if ( replacementType !== entry ) { requiresUpdate = true ; } } ) ; return requiresUpdate ? OverloadedFunctionType . create ( newOverloads ) : type ; } return type ; } transformTypeVar ( typeVar ) { return typeVar ; } transformVariadicTypeVar ( paramSpec ) { return undefined ; } transformParamSpec ( paramSpec ) { return undefined ; } transformUnion ( type ) { return type ; } private _transformTypeVarsInClassType ( classType , recursionSet , recursionLevel ) { if ( ClassType . getTypeParameters ( classType ) . length === 0 && ! ClassType . isSpecialBuiltIn ( classType ) ) { return classType ; } let newTypeArgs = [ ] ; let newVariadicTypeArgs ; let specializationNeeded = false ; const typeParams = ClassType . getTypeParameters ( classType ) ; const transformParamSpec = ( paramSpec ) => { const paramSpecValue = this . transformParamSpec ( paramSpec ) ; if ( paramSpecValue ) { specializationNeeded = true ; return convertParamSpecValueToType ( paramSpecValue ) ; } else { return paramSpec ; } } ; const wasTransformingTypeArg = this . _isTransformingTypeArg ; this . _isTransformingTypeArg = true ; if ( classType . typeArguments ) { newTypeArgs = classType . typeArguments . map ( ( oldTypeArgType ) => { if ( isTypeVar ( oldTypeArgType ) && oldTypeArgType . details . isParamSpec ) { return transformParamSpec ( oldTypeArgType ) ; } if ( isTypeVar ( oldTypeArgType ) && oldTypeArgType . details . isSynthesizedSelf && oldTypeArgType . details . boundType ) { const transformedSelf = this . apply ( oldTypeArgType . details . boundType , recursionSet , recursionLevel + 1 ) ; if ( transformedSelf !== oldTypeArgType . details . boundType ) { specializationNeeded = true ; return TypeVarType . cloneAsSpecializedSelf ( oldTypeArgType , transformedSelf ) ; } } let newTypeArgType = this . apply ( oldTypeArgType , recursionSet , recursionLevel + 1 ) ; if ( newTypeArgType !== oldTypeArgType ) { specializationNeeded = true ; if ( isTypeVar ( oldTypeArgType ) && isVariadicTypeVar ( oldTypeArgType ) && oldTypeArgType . isVariadicInUnion ) { newTypeArgType = _expandVariadicUnpackedUnion ( newTypeArgType ) ; } } return newTypeArgType ; } ) ; } else { typeParams . forEach ( ( typeParam ) => { let replacementType = typeParam ; if ( typeParam . details . isParamSpec ) { replacementType = transformParamSpec ( typeParam ) ; if ( replacementType !== typeParam ) { specializationNeeded = true ; } } else { const typeParamName = TypeVarType . getNameWithScope ( typeParam ) ; if ( ! recursionSet . has ( typeParamName ) ) { replacementType = this . transformTypeVar ( typeParam ) ; if ( replacementType !== typeParam ) { if ( ! this . _isTransformingTypeArg ) { recursionSet . add ( typeParamName ) ; replacementType = this . apply ( replacementType , recursionSet , recursionLevel + 1 ) ; recursionSet . delete ( typeParamName ) ; } specializationNeeded = true ; } } } newTypeArgs . push ( replacementType ) ; } ) ; } if ( ClassType . isTupleClass ( classType ) ) { if ( classType . tupleTypeArguments ) { newVariadicTypeArgs = [ ] ; classType . tupleTypeArguments . forEach ( ( oldTypeArgType ) => { const newTypeArgType = this . apply ( oldTypeArgType , recursionSet , recursionLevel + 1 ) ; if ( newTypeArgType !== oldTypeArgType ) { specializationNeeded = true ; } if ( isVariadicTypeVar ( oldTypeArgType ) && isClassInstance ( newTypeArgType ) && isTupleClass ( newTypeArgType ) && newTypeArgType . tupleTypeArguments ) { newVariadicTypeArgs ! . push ( ... newTypeArgType . tupleTypeArguments ) ; } else { newVariadicTypeArgs ! . push ( newTypeArgType ) ; } } ) ; } else if ( typeParams . length > 0 ) { newVariadicTypeArgs = this . transformVariadicTypeVar ( typeParams [ 0 ] ) ; if ( newVariadicTypeArgs ) { specializationNeeded = true ; } } } this . _isTransformingTypeArg = wasTransformingTypeArg ; if ( ! specializationNeeded ) { return classType ; } return ClassType . cloneForSpecialization ( classType , newTypeArgs , true , undefined , newVariadicTypeArgs ) ; } private _transformTypeVarsInFunctionType ( sourceType , recursionSet , recursionLevel ) { let functionType = sourceType ; if ( functionType . details . paramSpec ) { const paramSpec = this . transformParamSpec ( functionType . details . paramSpec ) ; if ( paramSpec ) { functionType = FunctionType . cloneForParamSpec ( functionType , paramSpec ) ; } } const declaredReturnType = functionType . specializedTypes && functionType . specializedTypes . returnType ? functionType . specializedTypes . returnType : functionType . details . declaredReturnType ; const specializedReturnType = declaredReturnType ? this . apply ( declaredReturnType , recursionSet , recursionLevel + 1 ) : undefined ; let typesRequiredSpecialization = declaredReturnType !== specializedReturnType ; const specializedParameters = { parameterTypes : [ ] , returnType : specializedReturnType , } ; if ( functionType . details . parameters . length >= 2 ) { const argsParam = functionType . details . parameters [ functionType . details . parameters . length - 2 ] ; const kwargsParam = functionType . details . parameters [ functionType . details . parameters . length - 1 ] ; const argsParamType = FunctionType . getEffectiveParameterType ( functionType , functionType . details . parameters . length - 2 ) ; const kwargsParamType = FunctionType . getEffectiveParameterType ( functionType , functionType . details . parameters . length - 1 ) ; if ( argsParam . category === ParameterCategory . VarArgList && kwargsParam . category === ParameterCategory . VarArgDictionary && isParamSpec ( argsParamType ) && isParamSpec ( kwargsParamType ) && isTypeSame ( argsParamType , kwargsParamType ) ) { const paramSpecType = this . transformParamSpec ( argsParamType ) ; if ( paramSpecType ) { functionType = FunctionType . cloneForParamSpecApplication ( functionType , paramSpecType ) ; } } } let variadicParamIndex ; let variadicTypesToUnpack ; for ( let i = 0 ; i < functionType . details . parameters . length ; i ++ ) { const paramType = FunctionType . getEffectiveParameterType ( functionType , i ) ; const specializedType = this . apply ( paramType , recursionSet , recursionLevel + 1 ) ; specializedParameters . parameterTypes . push ( specializedType ) ; if ( variadicParamIndex === undefined && isVariadicTypeVar ( paramType ) && functionType . details . parameters [ i ] . category === ParameterCategory . Simple ) { variadicParamIndex = i ; if ( isClassInstance ( specializedType ) && isTupleClass ( specializedType ) && specializedType . isTupleForUnpackedVariadicTypeVar ) { variadicTypesToUnpack = specializedType . tupleTypeArguments ; } } if ( paramType !== specializedType ) { typesRequiredSpecialization = true ; } } if ( ! typesRequiredSpecialization ) { return functionType ; } let specializedInferredReturnType ; if ( functionType . inferredReturnType ) { specializedInferredReturnType = this . apply ( functionType . inferredReturnType , recursionSet , recursionLevel + 1 ) ; } if ( ! variadicTypesToUnpack ) { return FunctionType . cloneForSpecialization ( functionType , specializedParameters , specializedInferredReturnType ) ; } const newFunctionType = FunctionType . createInstance ( '' , '' , '' , FunctionTypeFlags . SynthesizedMethod ) ; specializedParameters . parameterTypes . forEach ( ( paramType , index ) => { if ( index === variadicParamIndex ) { variadicTypesToUnpack ! . forEach ( ( unpackedType ) => { FunctionType . addParameter ( newFunctionType , { category : ParameterCategory . Simple , name : `__p${ newFunctionType . details . parameters . length }` , isNameSynthesized : true , type : unpackedType , hasDeclaredType : true , } ) ; } ) ; } else { const param = { ... functionType . details . parameters [ index ] } ; param . type = paramType ; if ( param . name && param . isNameSynthesized ) { param . name = `__p${ newFunctionType . details . parameters . length }` ; } FunctionType . addParameter ( newFunctionType , param ) ; } } ) ; newFunctionType . details . declaredReturnType = specializedParameters . returnType ; return newFunctionType ; } } class ApplySolvedTypeVarsTransformer extends TypeVarTransformer { constructor ( private _typeVarMap , private _unknownIfNotFound = false , private _useNarrowBoundOnly = false , private _eliminateUnsolvedInUnions = false ) { super ( ) ; } override transformTypeVar ( typeVar ) { if ( typeVar . scopeId && this . _typeVarMap . hasSolveForScope ( typeVar . scopeId ) ) { let replacement = this . _typeVarMap . getTypeVarType ( typeVar , this . _useNarrowBoundOnly ) ; if ( ! replacement && this . _useNarrowBoundOnly ) { const wideType = this . _typeVarMap . getTypeVarType ( typeVar ) ; if ( wideType ) { if ( containsLiteralType ( wideType , true ) ) { replacement = wideType ; } } } if ( replacement ) { if ( TypeBase . isInstantiable ( typeVar ) ) { replacement = convertToInstantiable ( replacement ) ; } return replacement ; } if ( this . _unknownIfNotFound ) { return UnknownType . create ( ) ; } } return typeVar ; } override transformUnion ( type ) { if ( this . _eliminateUnsolvedInUnions ) { const updatedUnion = mapSubtypes ( type , ( subtype ) => { if ( isTypeVar ( subtype ) && subtype . scopeId !== undefined && this . _typeVarMap . hasSolveForScope ( subtype . scopeId ) ) { return undefined ; } return subtype ; } ) ; return isNever ( updatedUnion ) ? type : updatedUnion ; } return type ; } override transformVariadicTypeVar ( typeVar ) { if ( ! typeVar . scopeId || ! this . _typeVarMap . hasSolveForScope ( typeVar . scopeId ) ) { return undefined ; } return this . _typeVarMap . getVariadicTypeVar ( typeVar ) ; } override transformParamSpec ( paramSpec ) { if ( ! paramSpec . scopeId || ! this . _typeVarMap . hasSolveForScope ( paramSpec . scopeId ) ) { return undefined ; } return this . _typeVarMap . getParamSpec ( paramSpec ) ; } } class ExpectedConstructorTypeTransformer extends TypeVarTransformer { static synthesizedTypeVarIndexForExpectedType = 1 ; dummyScopeId = '__expected_type_scope_id' ; dummyTypeVarPrefix = '__expected_type_' ; constructor ( private _typeVarMap , private _liveTypeVarScopes ) { super ( ) ; this . _typeVarMap . addSolveForScope ( this . dummyScopeId ) ; } private _isTypeVarLive ( typeVar ) { return this . _liveTypeVarScopes . some ( ( scopeId ) => typeVar . scopeId === scopeId ) ; } private _createDummyTypeVar ( prevTypeVar ) { if ( prevTypeVar . details . isSynthesized && prevTypeVar . details . name . startsWith ( this . dummyTypeVarPrefix ) ) { return prevTypeVar ; } const isInstance = TypeBase . isInstance ( prevTypeVar ) ; let newTypeVar = TypeVarType . createInstance ( `__expected_type_${ ExpectedConstructorTypeTransformer . synthesizedTypeVarIndexForExpectedType }` ) ; newTypeVar . details . isSynthesized = true ; newTypeVar . scopeId = this . dummyScopeId ; newTypeVar . nameWithScope = TypeVarType . makeNameWithScope ( newTypeVar . details . name , this . dummyScopeId ) ; if ( ! isInstance ) { newTypeVar = convertToInstantiable ( newTypeVar ) as TypeVarType ; } newTypeVar . details . boundType = prevTypeVar . details . boundType ; newTypeVar . details . constraints = prevTypeVar . details . constraints ; newTypeVar . details . variance = prevTypeVar . details . variance ; ExpectedConstructorTypeTransformer . synthesizedTypeVarIndexForExpectedType ++ ; return newTypeVar ; } override transformTypeVar ( typeVar ) { if ( this . _isTypeVarLive ( typeVar ) ) { return typeVar ; } return this . _createDummyTypeVar ( typeVar ) ; } }