import { CancellationToken } from 'vscode-languageserver' ; import { Commands } from '../commands/commands' ; import { throwIfCancellationRequested } from '../common/cancellationUtils' ; import { DiagnosticLevel } from '../common/configOptions' ; import { assert , fail } from '../common/debug' ; import { AddMissingOptionalToParamAction , DiagnosticAddendum } from '../common/diagnostic' ; import { DiagnosticRule } from '../common/diagnosticRules' ; import { convertOffsetsToRange } from '../common/positionUtils' ; import { PythonVersion } from '../common/pythonVersion' ; import { TextRange } from '../common/textRange' ; import { Localizer } from '../localization/localize' ; import { ArgumentCategory , ArrowCallableNode , AssignmentNode , AugmentedAssignmentNode , BinaryOperationNode , CallNode , CaseNode , ClassNode , ConstantNode , DecoratorNode , DictionaryNode , ExceptNode , ExpressionNode , ForNode , FunctionNode , ImportAsNode , ImportFromAsNode , ImportFromNode , IndexNode , isExpressionNode , LambdaNode , ListComprehensionNode , ListNode , MatchNode , MemberAccessNode , NameNode , ParameterCategory , ParameterNode , ParseNode , ParseNodeType , RaiseNode , SetNode , SliceNode , StringListNode , TernaryNode , TupleNode , TypeAnnotationNode , UnaryOperationNode , WithItemNode , YieldFromNode , YieldNode , } from '../parser/parseNodes' ; import { ParseOptions , Parser } from '../parser/parser' ; import { KeywordType , OperatorType , StringTokenFlags } from '../parser/tokenizerTypes' ; import * as DeclarationUtils from './aliasDeclarationUtils' ; import { AnalyzerFileInfo , ImportLookup } from './analyzerFileInfo' ; import * as AnalyzerNodeInfo from './analyzerNodeInfo' ; import { CodeFlowAnalyzer , FlowNodeTypeResult , getCodeFlowEngine } from './codeFlowEngine' ; import { CodeFlowReferenceExpressionNode , createKeyForReference , FlowNode , isCodeFlowSupportedForReference , } from './codeFlowTypes' ; import { applyConstructorTransform } from './constructorTransform' ; import { applyDataClassDecorator , applyDataClassDefaultBehaviors , applyDataClassMetaclassBehaviorOverrides , getDataclassDecoratorBehaviors , synthesizeDataClassMethods , validateDataClassTransformDecorator , } from './dataClasses' ; import { ClassDeclaration , Declaration , DeclarationType , FunctionDeclaration , ModuleLoaderActions , VariableDeclaration , } from './declaration' ; import { createSynthesizedAliasDeclaration , getDeclarationsWithUsesLocalNameRemoved , isExplicitTypeAliasDeclaration , isFinalVariableDeclaration , isPossibleTypeAliasDeclaration , } from './declarationUtils' ; import { applyFunctionTransform } from './functionTransform' ; import { createNamedTupleType } from './namedTuples' ; import * as ParseTreeUtils from './parseTreeUtils' ; import { assignTypeToPatternTargets , narrowTypeBasedOnPattern } from './patternMatching' ; import { Scope , ScopeType , SymbolWithScope } from './scope' ; import * as ScopeUtils from './scopeUtils' ; import { evaluateStaticBoolExpression } from './staticExpressions' ; import { indeterminateSymbolId , Symbol , SymbolFlags } from './symbol' ; import { isConstantName , isPrivateOrProtectedName , isSingleDunderName } from './symbolNameUtils' ; import { getLastTypedDeclaredForSymbol , isFinalVariable } from './symbolUtils' ; import { CachedType , IncompleteTypeTracker , isIncompleteType , SpeculativeTypeTracker , TypeCache } from './typeCache' ; import { assignToTypedDict , canAssignTypedDict , createTypedDictType , getTypedDictMembersForClass , getTypeFromIndexedTypedDict , synthesizeTypedDictClassMethods , } from './typedDicts' ; import { AbstractMethod , AnnotationTypeOptions , CallSignature , CallSignatureInfo , ClassTypeResult , EffectiveTypeResult , EvaluatorFlags , EvaluatorUsage , ExpectedTypeResult , FunctionArgument , FunctionTypeResult , TypeArgumentResult , TypeEvaluator , TypeResult , ValidateArgTypeParams , } from './typeEvaluatorTypes' ; import * as TypePrinter from './typePrinter' ; import { AnyType , ClassType , ClassTypeFlags , combineTypes , DataClassBehaviors , EnumLiteral , findSubtype , FunctionParameter , FunctionType , FunctionTypeFlags , InheritanceChain , isAny , isAnyOrUnknown , isClass , isClassInstance , isFunction , isInstantiableClass , isModule , isNever , isNoneInstance , isNoneTypeClass , isOverloadedFunction , isParamSpec , isTypeSame , isTypeVar , isUnbound , isUnion , isUnknown , isVariadicTypeVar , LiteralValue , maxTypeRecursionCount , ModuleType , NeverType , NoneType , OverloadedFunctionType , ParamSpecEntry , removeNoneFromUnion , removeUnbound , Type , TypeBase , TypeCategory , TypeCondition , TypedDictEntry , TypeSourceId , TypeVarScopeId , TypeVarScopeType , TypeVarType , UnboundType , UnionType , UnknownType , Variance , WildcardTypeVarScopeId , } from './types' ; import { addConditionToType , addTypeVarsToListIfUnique , applySolvedTypeVars , areTypesSame , buildTypeVarMapFromSpecializedClass , CanAssignFlags , ClassMember , ClassMemberLookupFlags , combineSameSizedTuples , computeMroLinearization , containsLiteralType , containsUnknown , convertParamSpecValueToType , convertToInstance , convertToInstantiable , derivesFromClassRecursive , doForEachSubtype , explodeGenericClass , getDeclaredGeneratorReturnType , getDeclaredGeneratorSendType , getGeneratorTypeArgs , getParameterListDetails , getSpecializedTupleType , getTypeCondition , getTypeVarArgumentsRecursive , getTypeVarScopeId , isEllipsisType , isLiteralType , isLiteralTypeOrUnion , isNoReturnType , isOpenEndedTupleClass , isOptionalType , isPartlyUnknown , isProperty , isTupleClass , isTypeAliasPlaceholder , isTypeAliasRecursive , isUnionableType , lookUpClassMember , lookUpObjectMember , mapSubtypes , ParameterListDetails , ParameterSource , partiallySpecializeType , populateTypeVarMapForSelfType , removeNoReturnFromUnion , removeParamSpecVariadicsFromFunction , removeParamSpecVariadicsFromSignature , requiresSpecialization , requiresTypeArguments , setTypeArgumentsRecursive , specializeClassType , specializeForBaseClass , specializeTupleClass , stripLiteralValue , synthesizeTypeVarForSelfCls , transformExpectedTypeForConstructor , transformPossibleRecursiveTypeAlias , } from './typeUtils' ; import { TypeVarMap } from './typeVarMap' ; const enum MemberAccessFlags { None = 0 , AccessClassMembersOnly = 1 << 0 , SkipBaseClasses = 1 << 1 , SkipObjectBaseClass = 1 << 2 , DisallowClassVarWrites = 1 << 3 , TreatConstructorAsClassMethod = 1 << 4 , ConsiderMetaclassOnly = 1 << 5 , SkipAttributeAccessOverride = 1 << 6 , SkipOriginalClass = 1 << 7 , SkipTypeBaseClass = 1 << 8 } interface EffectiveTypeCacheEntry { usageNodeId : number | undefined ; useLastDecl : boolean ; result : EffectiveTypeResult ; } interface MatchArgsToParamsResult { overload : FunctionType ; overloadIndex : number ; argumentErrors : boolean ; isTypeIncomplete : boolean ; argParams : ValidateArgTypeParams [ ] ; activeParam ? : FunctionParameter | undefined ; paramSpecTarget ? : TypeVarType | undefined ; paramSpecArgList ? : FunctionArgument [ ] | undefined ; relevance : number ; } interface ArgResult { isCompatible : boolean ; isTypeIncomplete ? : boolean | undefined ; skippedOverloadArg ? : boolean ; } interface ClassMemberLookup { type : Type ; isTypeIncomplete : boolean ; isClassMember : boolean ; classType ? : ClassType | UnknownType ; isClassVar : boolean ; isAsymmetricDescriptor : boolean ; } export interface DescriptorTypeResult { type : Type ; isAsymmetricDescriptor : boolean ; } interface AliasMapEntry { alias : string ; module : 'builtins' | 'collections' | 'self' ; } interface ParamAssignmentInfo { argsNeeded : number ; argsReceived : number ; isPositionalOnly : boolean ; } interface CallResult { returnType ? : Type | undefined ; isTypeIncomplete ? : boolean | undefined ; argumentErrors : boolean ; activeParam ? : FunctionParameter | undefined ; specializedInitSelfType ? : Type | undefined ; } const binaryOperatorMap = { [ OperatorType . Add ] : [ '__add__' , '__radd__' , false ] , [ OperatorType . Subtract ] : [ '__sub__' , '__rsub__' , false ] , [ OperatorType . Multiply ] : [ '__mul__' , '__rmul__' , false ] , [ OperatorType . FloorDivide ] : [ '__floordiv__' , '__rfloordiv__' , false ] , [ OperatorType . Divide ] : [ '__truediv__' , '__rtruediv__' , false ] , [ OperatorType . Mod ] : [ '__mod__' , '__rmod__' , false ] , [ OperatorType . Power ] : [ '__pow__' , '__rpow__' , false ] , [ OperatorType . MatrixMultiply ] : [ '__matmul__' , '__rmatmul__' , false ] , [ OperatorType . BitwiseAnd ] : [ '__and__' , '__rand__' , false ] , [ OperatorType . BitwiseOr ] : [ '__or__' , '__ror__' , false ] , [ OperatorType . BitwiseXor ] : [ '__xor__' , '__rxor__' , false ] , [ OperatorType . LeftShift ] : [ '__lshift__' , '__rlshift__' , false ] , [ OperatorType . RightShift ] : [ '__rshift__' , '__rrshift__' , false ] , [ OperatorType . Equals ] : [ '__eq__' , '__ne__' , true ] , [ OperatorType . NotEquals ] : [ '__ne__' , '__eq__' , true ] , [ OperatorType . LessThan ] : [ '__lt__' , '__ge__' , true ] , [ OperatorType . LessThanOrEqual ] : [ '__le__' , '__gt__' , true ] , [ OperatorType . GreaterThan ] : [ '__gt__' , '__le__' , true ] , [ OperatorType . GreaterThanOrEqual ] : [ '__ge__' , '__lt__' , true ] , } ; const booleanOperatorMap = { [ OperatorType . And ] : false , [ OperatorType . Or ] : false , [ OperatorType . Is ] : true , [ OperatorType . IsNot ] : true , [ OperatorType . In ] : true , [ OperatorType . NotIn ] : true , } ; const nonSubscriptableBuiltinTypes = new Map ( [ [ 'asyncio.futures.Future' , PythonVersion . V3_9 ] , [ 'asyncio.tasks.Task' , PythonVersion . V3_9 ] , [ 'builtins.dict' , PythonVersion . V3_9 ] , [ 'builtins.frozenset' , PythonVersion . V3_9 ] , [ 'builtins.list' , PythonVersion . V3_9 ] , [ 'builtins._PathLike' , PythonVersion . V3_9 ] , [ 'builtins.set' , PythonVersion . V3_9 ] , [ 'builtins.tuple' , PythonVersion . V3_9 ] , [ 'collections.ChainMap' , PythonVersion . V3_9 ] , [ 'collections.Counter' , PythonVersion . V3_9 ] , [ 'collections.defaultdict' , PythonVersion . V3_9 ] , [ 'collections.DefaultDict' , PythonVersion . V3_9 ] , [ 'collections.deque' , PythonVersion . V3_9 ] , [ 'collections.OrderedDict' , PythonVersion . V3_9 ] , [ 'queue.Queue' , PythonVersion . V3_9 ] , ] ) ; const typePromotions = new Map ( [ [ 'builtins.float' , [ 'builtins.int' ] ] , [ 'builtins.complex' , [ 'builtins.float' , 'builtins.int' ] ] , [ 'builtins.bytes' , [ 'builtins.bytearray' , 'builtins.memoryview' ] ] , ] ) ; interface SymbolResolutionStackEntry { symbolId : number ; declaration : Declaration ; isResultValid : boolean ; partialType ? : Type | undefined ; } interface ReturnTypeInferenceContext { functionNode : FunctionNode ; codeFlowAnalyzer : CodeFlowAnalyzer ; } const maxReturnTypeInferenceStackSize = 2 ; const maxReturnTypeInferenceArgumentCount = 6 ; const maxReturnTypeInferenceCodeFlowComplexity = 15 ; const maxEntriesToUseForInference = 64 ; const maxSubtypesForInferredType = 64 ; const maxOverloadUnionExpansionCount = 64 ; const verifyTypeCacheEvaluatorFlags = false ; export interface EvaluatorOptions { disableInferenceForPyTypedSources : boolean ; printTypeFlags : TypePrinter . PrintTypeFlags ; logCalls : boolean ; minimumLoggingThreshold : number ; analyzeUnannotatedFunctions : boolean ; evaluateUnknownImportsAsAny : boolean ; verifyTypeCacheEvaluatorFlags : boolean ; } export function createTypeEvaluator ( importLookup , evaluatorOptions ) { const symbolResolutionStack = [ ] ; const functionRecursionMap = new Map < number , true > ( ) ; const codeFlowAnalyzerCache = new Map < number , CodeFlowAnalyzer > ( ) ; const typeCache = new Map < number , CachedType > ( ) ; const typeCacheFlags = new Map < number , EvaluatorFlags > ( ) ; const asymmetricDescriptorAssignmentCache = new Set < number > ( ) ; const expectedTypeCache = new Map < number , Type > ( ) ; const speculativeTypeTracker = new SpeculativeTypeTracker ( ) ; const effectiveTypeCache = new Map < number , EffectiveTypeCacheEntry [ ] > ( ) ; const suppressedNodeStack = [ ] ; const incompleteTypeTracker = new IncompleteTypeTracker ( ) ; let cancellationToken ; let isBasicTypesInitialized = false ; let noneType ; let unionType ; let objectType ; let typeClassType ; let functionObj ; let tupleClassType ; let boolClassType ; let strClassType ; let dictClassType ; let typedDictClassType ; let incompleteTypeCache ; const returnTypeInferenceContextStack = [ ] ; let returnTypeInferenceTypeCache ; function runWithCancellationToken < T > ( token , callback ) { try { cancellationToken = token ; return callback ( ) ; } finally { cancellationToken = undefined ; } } function checkForCancellation ( ) { if ( cancellationToken ) { throwIfCancellationRequested ( cancellationToken ) ; } } function getTypeCacheSize ( ) { return typeCache . size ; } function isTypeCached ( node ) { let cachedType ; if ( returnTypeInferenceTypeCache && isNodeInReturnTypeInferenceContext ( node ) ) { cachedType = returnTypeInferenceTypeCache . get ( node . id ) ; } else { cachedType = typeCache . get ( node . id ) ; } return cachedType !== undefined ; } function readTypeCache ( node , flags ) { let cachedType ; if ( returnTypeInferenceTypeCache && isNodeInReturnTypeInferenceContext ( node ) ) { cachedType = returnTypeInferenceTypeCache . get ( node . id ) ; } else { cachedType = typeCache . get ( node . id ) ; } if ( cachedType === undefined ) { return undefined ; } if ( evaluatorOptions . verifyTypeCacheEvaluatorFlags || verifyTypeCacheEvaluatorFlags ) { if ( flags !== undefined ) { const expectedFlags = typeCacheFlags . get ( node . id ) ; if ( expectedFlags !== undefined && flags !== expectedFlags ) { fail ( `Type cache flag mismatch for node type ${ node . nodeType }: ` + `cached flags = ${ expectedFlags }, access flags = ${ flags }` ) ; } } } assert ( ! isIncompleteType ( cachedType ) ) ; return cachedType as Type ; } function writeTypeCache ( node , type , flags , isIncomplete , expectedType ? , allowSpeculativeCaching = false ) { if ( isIncomplete ) { if ( incompleteTypeCache ) { incompleteTypeCache . set ( node . id , type ) ; } return ; } const typeCacheToUse = returnTypeInferenceTypeCache && isNodeInReturnTypeInferenceContext ( node ) ? returnTypeInferenceTypeCache : typeCache ; typeCacheToUse . set ( node . id , type ) ; if ( evaluatorOptions . verifyTypeCacheEvaluatorFlags || verifyTypeCacheEvaluatorFlags ) { if ( typeCacheToUse === typeCache && flags !== undefined ) { typeCacheFlags . set ( node . id , flags ) ; } } if ( speculativeTypeTracker . isSpeculative ( node ) ) { speculativeTypeTracker . trackEntry ( typeCacheToUse , node . id ) ; if ( allowSpeculativeCaching ) { speculativeTypeTracker . addSpeculativeType ( node , type , expectedType ) ; } } incompleteTypeTracker . trackEntry ( typeCacheToUse , node . id ) ; } function deleteTypeCacheEntry ( node ) { const typeCacheToUse = returnTypeInferenceTypeCache && isNodeInReturnTypeInferenceContext ( node ) ? returnTypeInferenceTypeCache : typeCache ; typeCacheToUse . delete ( node . id ) ; } function setTypeForNode ( node , type = UnknownType . create ( ) , flags = EvaluatorFlags . None ) { writeTypeCache ( node , type , flags , false ) ; } function setAsymmetricDescriptorAssignment ( node ) { if ( speculativeTypeTracker . isSpeculative ( undefined ) ) { return ; } asymmetricDescriptorAssignmentCache . add ( node . id ) ; } function isAsymmetricDescriptorAssignment ( node ) { return asymmetricDescriptorAssignmentCache . has ( node . id ) ; } function isNodeInReturnTypeInferenceContext ( node ) { const stackSize = returnTypeInferenceContextStack . length ; if ( stackSize === 0 ) { return false ; } const contextNode = returnTypeInferenceContextStack [ stackSize - 1 ] ; let curNode = node ; while ( curNode ) { if ( curNode === contextNode . functionNode ) { return true ; } curNode = curNode . parent ; } return false ; } function getCodeFlowAnalyzerForReturnTypeInferenceContext ( ) { const stackSize = returnTypeInferenceContextStack . length ; assert ( stackSize > 0 ) ; const contextNode = returnTypeInferenceContextStack [ stackSize - 1 ] ; return contextNode . codeFlowAnalyzer ; } function getIndexOfSymbolResolution ( symbol , declaration ) { return symbolResolutionStack . findIndex ( ( entry ) => entry . symbolId === symbol . id && entry . declaration === declaration ) ; } function pushSymbolResolution ( symbol , declaration ) { const index = getIndexOfSymbolResolution ( symbol , declaration ) ; if ( index >= 0 ) { for ( let i = index + 1 ; i < symbolResolutionStack . length ; i ++ ) { symbolResolutionStack [ i ] . isResultValid = false ; } return false ; } symbolResolutionStack . push ( { symbolId : symbol . id , declaration , isResultValid : true , } ) ; return true ; } function popSymbolResolution ( symbol ) { const poppedEntry = symbolResolutionStack . pop ( ) ! ; assert ( poppedEntry . symbolId === symbol . id ) ; return poppedEntry . isResultValid ; } function setSymbolResolutionPartialType ( symbol , declaration , type ) { const index = getIndexOfSymbolResolution ( symbol , declaration ) ; if ( index >= 0 ) { symbolResolutionStack [ index ] . partialType = type ; } } function getSymbolResolutionPartialType ( symbol , declaration ) { const index = getIndexOfSymbolResolution ( symbol , declaration ) ; if ( index >= 0 ) { return symbolResolutionStack [ index ] . partialType ; } return undefined ; } function getType ( node ) { return evaluateTypeForSubnode ( node , ( ) => { evaluateTypesForExpressionInContext ( node ) ; } ) ?. type ; } function getExpectedType ( node ) { evaluateTypesForExpressionInContext ( node ) ; let curNode = node ; while ( curNode !== undefined ) { const expectedType = expectedTypeCache . get ( curNode . id ) ; if ( expectedType ) { return { type : expectedType , node : curNode , } ; } curNode = curNode . parent ; } return undefined ; } function initializedBasicTypes ( node ) { if ( ! isBasicTypesInitialized ) { isBasicTypesInitialized = true ; objectType = getBuiltInObject ( node , 'object' ) ; typeClassType = getBuiltInType ( node , 'type' ) ; functionObj = getBuiltInObject ( node , 'function' ) ; getTypingType ( node , 'Collection' ) ; noneType = getTypeshedType ( node , 'NoneType' ) || AnyType . create ( ) ; tupleClassType = getBuiltInType ( node , 'tuple' ) ; boolClassType = getBuiltInType ( node , 'bool' ) ; strClassType = getBuiltInType ( node , 'str' ) ; dictClassType = getBuiltInType ( node , 'dict' ) ; typedDictClassType = getTypingType ( node , '_TypedDict' ) ; } } function getTypeOfExpression ( node , expectedType ? , flags = EvaluatorFlags . None ) { const cachedType = readTypeCache ( node , flags ) ; if ( cachedType ) { return { type : cachedType , node } ; } else { const speculativeCachedType = speculativeTypeTracker . getSpeculativeType ( node , expectedType ) ; if ( speculativeCachedType ) { return { type : speculativeCachedType , node } ; } } checkForCancellation ( ) ; const expectedTypeAlt = transformPossibleRecursiveTypeAlias ( expectedType ) ; initializedBasicTypes ( node ) ; let typeResult ; let reportExpectingTypeErrors = ( flags & EvaluatorFlags . ExpectingType ) !== 0 ; switch ( node . nodeType ) { case ParseNodeType . Name : { typeResult = getTypeFromName ( node , flags ) ; break ; } case ParseNodeType . MemberAccess : { typeResult = getTypeFromMemberAccess ( node , flags ) ; if ( ! isTypeAliasPlaceholder ( typeResult . type ) ) { writeTypeCache ( node . memberName , typeResult . type , flags , ! ! typeResult . isIncomplete ) ; } break ; } case ParseNodeType . Index : { typeResult = getTypeFromIndex ( node , flags ) ; break ; } case ParseNodeType . Call : { if ( ( flags & EvaluatorFlags . ExpectingTypeAnnotation ) !== 0 ) { getTypeFromCall ( node , expectedTypeAlt ) ; addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeAnnotationCall ( ) , node ) ; typeResult = { node , type : UnknownType . create ( ) } ; } else { typeResult = getTypeFromCall ( node , expectedTypeAlt ) ; } break ; } case ParseNodeType . Tuple : { typeResult = getTypeFromTuple ( node , expectedTypeAlt , flags ) ; break ; } case ParseNodeType . Constant : { typeResult = getTypeFromConstant ( node , flags ) ; break ; } case ParseNodeType . StringList : { const expectingType = ( flags & EvaluatorFlags . EvaluateStringLiteralAsType ) !== 0 && ! isAnnotationLiteralValue ( node ) ; if ( expectingType ) { if ( node . typeAnnotation ) { typeResult = getTypeOfExpression ( node . typeAnnotation , undefined , flags | EvaluatorFlags . AllowForwardReferences | EvaluatorFlags . NotParsedByInterpreter | EvaluatorFlags . ExpectingType ) ; } else if ( ! node . typeAnnotation && node . strings . length === 1 ) { const expr = parseStringAsTypeAnnotation ( node ) ; if ( expr ) { typeResult = getTypeOfExpression ( expr , undefined , flags | EvaluatorFlags . AllowForwardReferences | EvaluatorFlags . NotParsedByInterpreter | EvaluatorFlags . ExpectingType ) ; } } if ( ! typeResult ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . expectedTypeNotString ( ) , node ) ; typeResult = { node , type : UnknownType . create ( ) } ; } reportExpectingTypeErrors = false ; } else { node . strings . forEach ( ( str ) => { if ( str . nodeType === ParseNodeType . FormatString ) { str . expressions . forEach ( ( expr ) => { getTypeOfExpression ( expr ) ; } ) ; } } ) ; const isBytes = ( node . strings [ 0 ] . token . flags & StringTokenFlags . Bytes ) !== 0 ; if ( node . strings . some ( ( str ) => str . nodeType === ParseNodeType . FormatString ) ) { typeResult = { node , type : getBuiltInObject ( node , isBytes ? 'bytes' : 'str' ) , } ; } else { typeResult = { node , type : cloneBuiltinObjectWithLiteral ( node , isBytes ? 'bytes' : 'str' , node . strings . map ( ( s ) => s . value ) . join ( '' ) ) , } ; } } break ; } case ParseNodeType . Number : { if ( node . isImaginary ) { typeResult = { node , type : getBuiltInObject ( node , 'complex' ) } ; } else if ( node . isInteger ) { typeResult = { node , type : cloneBuiltinObjectWithLiteral ( node , 'int' , node . value ) } ; } else { typeResult = { node , type : getBuiltInObject ( node , 'float' ) } ; } break ; } case ParseNodeType . Ellipsis : { if ( ( flags & EvaluatorFlags . ConvertEllipsisToAny ) !== 0 ) { typeResult = { type : AnyType . create ( true ) , node } ; } else if ( ( flags & EvaluatorFlags . ConvertEllipsisToUnknown ) !== 0 ) { typeResult = { type : UnknownType . create ( ) , node } ; } else { const ellipsisType = getBuiltInObject ( node , 'ellipsis' ) || AnyType . create ( ) ; typeResult = { type : ellipsisType , node } ; } break ; } case ParseNodeType . UnaryOperation : { typeResult = getTypeFromUnaryOperation ( node , expectedTypeAlt ) ; break ; } case ParseNodeType . BinaryOperation : { typeResult = getTypeFromBinaryOperation ( node , expectedTypeAlt , flags ) ; break ; } case ParseNodeType . AugmentedAssignment : { typeResult = getTypeFromAugmentedAssignment ( node , expectedTypeAlt ) ; assignTypeToExpression ( node . destExpression , typeResult . type , ! ! typeResult . isIncomplete , node . rightExpression ) ; break ; } case ParseNodeType . List : case ParseNodeType . Set : { typeResult = getTypeFromListOrSet ( node , expectedTypeAlt ) ; break ; } case ParseNodeType . Slice : { typeResult = getTypeFromSlice ( node ) ; break ; } case ParseNodeType . Await : { const exprTypeResult = getTypeOfExpression ( node . expression , undefined , flags ) ; typeResult = { type : getTypeFromAwaitable ( exprTypeResult . type , node . expression ) , node , } ; if ( exprTypeResult . isIncomplete ) { typeResult . isIncomplete = true ; } break ; } case ParseNodeType . Ternary : { typeResult = getTypeFromTernary ( node , flags , expectedTypeAlt ) ; break ; } case ParseNodeType . ListComprehension : { typeResult = getTypeFromListComprehension ( node , expectedTypeAlt ) ; break ; } case ParseNodeType . Dictionary : { typeResult = getTypeFromDictionary ( node , expectedTypeAlt ) ; break ; } case ParseNodeType . Lambda : { typeResult = getTypeFromLambda ( node , expectedTypeAlt ) ; break ; } case ParseNodeType . ArrowCallable : { typeResult = getTypeFromArrowCallable ( node , flags ) ; break ; } case ParseNodeType . Assignment : { typeResult = getTypeOfExpression ( node . rightExpression ) ; assignTypeToExpression ( node . leftExpression , typeResult . type , false , node . rightExpression , true ) ; break ; } case ParseNodeType . AssignmentExpression : { typeResult = getTypeOfExpression ( node . rightExpression ) ; assignTypeToExpression ( node . name , typeResult . type , false , node . rightExpression , true ) ; break ; } case ParseNodeType . Yield : { typeResult = getTypeFromYield ( node ) ; break ; } case ParseNodeType . YieldFrom : { typeResult = getTypeFromYieldFrom ( node ) ; break ; } case ParseNodeType . Unpack : { let iterExpectedType ; if ( expectedTypeAlt ) { const iterableType = getBuiltInType ( node , 'Iterable' ) ; if ( iterableType && isInstantiableClass ( iterableType ) ) { iterExpectedType = ClassType . cloneAsInstance ( ClassType . cloneForSpecialization ( iterableType , [ expectedTypeAlt ] , true ) ) ; } } const iterTypeResult = getTypeOfExpression ( node . expression , iterExpectedType , flags ) ; const iterType = iterTypeResult . type ; if ( ( flags & EvaluatorFlags . TypeVarTupleDisallowed ) === 0 && isVariadicTypeVar ( iterType ) && ! iterType . isVariadicUnpacked ) { typeResult = { type : TypeVarType . cloneForUnpacked ( iterType ) , node } ; } else { const type = getTypeFromIterator ( iterType , false , node ) || UnknownType . create ( ) ; typeResult = { type , unpackedType : iterType , node , isIncomplete : iterTypeResult . isIncomplete } ; } break ; } case ParseNodeType . TypeAnnotation : { typeResult = getTypeOfExpression ( node . typeAnnotation , undefined , EvaluatorFlags . EvaluateStringLiteralAsType | EvaluatorFlags . ParamSpecDisallowed | EvaluatorFlags . TypeVarTupleDisallowed | EvaluatorFlags . ExpectingType | EvaluatorFlags . ExpectingTypeAnnotation | EvaluatorFlags . VariableTypeAnnotation ) ; break ; } case ParseNodeType . Error : { suppressDiagnostics ( node , ( ) => { if ( node . child ) { getTypeOfExpression ( node . child ) ; } } ) ; typeResult = { type : UnknownType . create ( ) , node } ; break ; } } if ( ! typeResult ) { fail ( `Unhandled expression type '${ ParseTreeUtils . printExpression ( node ) }'` ) ; } if ( reportExpectingTypeErrors && ! typeResult . isIncomplete ) { if ( flags & EvaluatorFlags . TypeVarTupleDisallowed ) { if ( isTypeVar ( typeResult . type ) && typeResult . type . details . isVariadic && ! typeResult . type . isVariadicInUnion ) { addError ( Localizer . Diagnostic . typeVarTupleContext ( ) , node ) ; typeResult . type = UnknownType . create ( ) ; } } if ( ! TypeBase . isInstantiable ( typeResult . type ) ) { const isEmptyVariadic = isClassInstance ( typeResult . type ) && ClassType . isTupleClass ( typeResult . type ) && typeResult . type . tupleTypeArguments ?. length === 0 ; if ( ! isEmptyVariadic ) { addExpectedClassDiagnostic ( typeResult . type , node ) ; typeResult . type = UnknownType . create ( ) ; } } } if ( flags & EvaluatorFlags . DisallowRecursiveTypeAliasPlaceholder ) { if ( isTypeAliasPlaceholder ( typeResult . type ) ) { typeResult . type . details . illegalRecursionDetected = true ; } } if ( ! isTypeAliasPlaceholder ( typeResult . type ) ) { writeTypeCache ( node , typeResult . type , flags , ! ! typeResult . isIncomplete , expectedType , true ) ; if ( expectedType && ! isAnyOrUnknown ( expectedType ) ) { expectedTypeCache . set ( node . id , expectedType ) ; } } return typeResult ; } function isAnnotationEvaluationPostponed ( fileInfo ) { return ( fileInfo . futureImports . get ( 'annotations' ) !== undefined || fileInfo . executionEnvironment . pythonVersion >= PythonVersion . V3_11 || fileInfo . isStubFile ) ; } function getTypeOfAnnotation ( node , options ? ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; if ( fileInfo . isTypingStubFile || fileInfo . isTypingExtensionsStubFile ) { const specialType = handleTypingStubTypeAnnotation ( node ) ; if ( specialType ) { return specialType ; } } let evaluatorFlags = EvaluatorFlags . ExpectingType | EvaluatorFlags . ExpectingTypeAnnotation | EvaluatorFlags . ConvertEllipsisToAny | EvaluatorFlags . EvaluateStringLiteralAsType ; if ( options ?. isVariableAnnotation ) { evaluatorFlags |= EvaluatorFlags . VariableTypeAnnotation ; } if ( ! options ?. allowFinal ) { evaluatorFlags |= EvaluatorFlags . FinalDisallowed ; } if ( ! options ?. allowClassVar ) { evaluatorFlags |= EvaluatorFlags . ClassVarDisallowed ; } if ( ! options ?. allowTypeVarTuple ) { evaluatorFlags |= EvaluatorFlags . TypeVarTupleDisallowed ; } if ( ! options ?. allowParamSpec ) { evaluatorFlags |= EvaluatorFlags . ParamSpecDisallowed ; } if ( options ?. associateTypeVarsWithScope ) { evaluatorFlags |= EvaluatorFlags . AssociateTypeVarsWithCurrentScope ; } else { evaluatorFlags |= EvaluatorFlags . DisallowTypeVarsWithoutScopeId ; } if ( options ?. disallowRecursiveTypeAlias ) { evaluatorFlags |= EvaluatorFlags . DisallowRecursiveTypeAliasPlaceholder ; } if ( isAnnotationEvaluationPostponed ( fileInfo ) ) { evaluatorFlags |= EvaluatorFlags . AllowForwardReferences ; } if ( node ?. parent ?. nodeType === ParseNodeType . Assignment && node . parent . typeAnnotationComment === node ) { evaluatorFlags |= EvaluatorFlags . AllowForwardReferences | EvaluatorFlags . NotParsedByInterpreter ; } else if ( node ?. parent ?. nodeType === ParseNodeType . FunctionAnnotation ) { if ( node . parent . returnTypeAnnotation === node || node . parent . paramTypeAnnotations . some ( ( n ) => n === node ) ) { evaluatorFlags |= EvaluatorFlags . AllowForwardReferences | EvaluatorFlags . NotParsedByInterpreter ; } } else if ( node ?. parent ?. nodeType === ParseNodeType . Parameter ) { if ( node . parent . typeAnnotationComment === node ) { evaluatorFlags |= EvaluatorFlags . AllowForwardReferences | EvaluatorFlags . NotParsedByInterpreter ; } } const annotationType = getTypeOfExpression ( node , undefined , evaluatorFlags ) . type ; if ( isModule ( annotationType ) ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . moduleAsType ( ) , node ) ; } return convertToInstance ( annotationType ) ; } function getTypeFromDecorator ( node , functionOrClassType ) { let flags = AnalyzerNodeInfo . getFileInfo ( node ) . isStubFile ? EvaluatorFlags . AllowForwardReferences : EvaluatorFlags . None ; if ( node . expression . nodeType !== ParseNodeType . Call ) { flags |= EvaluatorFlags . DoNotSpecialize ; } const decoratorTypeResult = getTypeOfExpression ( node . expression , undefined , flags ) ; if ( isInstantiableClass ( decoratorTypeResult . type ) && ClassType . isBuiltIn ( decoratorTypeResult . type , 'classmethod' ) && isProperty ( functionOrClassType ) ) { return functionOrClassType ; } const argList = [ { argumentCategory : ArgumentCategory . Simple , type : functionOrClassType , } , ] ; const returnType = validateCallArguments ( node . expression , argList , decoratorTypeResult . type , undefined , true ) . returnType || UnknownType . create ( ) ; if ( isFunction ( returnType ) && ! returnType . details . declaredReturnType ) { if ( ! returnType . details . parameters . some ( ( param , index ) => { if ( ! param . name || param . hasDeclaredType ) { return true ; } if ( param . category !== ParameterCategory . Simple ) { return false ; } return index !== 0 || ! param . isTypeInferred ; } ) ) { return functionOrClassType ; } } if ( isPartlyUnknown ( returnType ) ) { if ( isFunction ( decoratorTypeResult . type ) ) { if ( ! decoratorTypeResult . type . details . parameters . find ( ( param ) => param . typeAnnotation !== undefined ) && decoratorTypeResult . type . details . declaredReturnType === undefined ) { return functionOrClassType ; } } } return returnType ; } function canBeFalsy ( type , recursionLevel = 0 ) { if ( recursionLevel > maxTypeRecursionCount ) { return true ; } switch ( type . category ) { case TypeCategory . Unbound : case TypeCategory . Unknown : case TypeCategory . Any : case TypeCategory . Never : case TypeCategory . None : { return true ; } case TypeCategory . Union : { return findSubtype ( type , ( subtype ) => canBeFalsy ( subtype , recursionLevel + 1 ) ) !== undefined ; } case TypeCategory . Function : case TypeCategory . OverloadedFunction : case TypeCategory . Module : case TypeCategory . TypeVar : { return false ; } case TypeCategory . Class : { if ( TypeBase . isInstantiable ( type ) ) { return false ; } if ( isTupleClass ( type ) && type . tupleTypeArguments ) { return isOpenEndedTupleClass ( type ) || type . tupleTypeArguments . length === 0 ; } if ( ClassType . isBuiltIn ( type , 'bool' ) && type . literalValue !== undefined ) { return type . literalValue === false ; } const lenMethod = lookUpObjectMember ( type , '__len__' ) ; if ( lenMethod ) { return true ; } const boolMethod = lookUpObjectMember ( type , '__bool__' ) ; if ( boolMethod ) { const boolMethodType = getTypeOfMember ( boolMethod ) ; if ( isFunction ( boolMethodType ) && boolMethodType . details . declaredReturnType ) { const returnType = boolMethodType . details . declaredReturnType ; if ( isClassInstance ( returnType ) && ClassType . isBuiltIn ( returnType , 'bool' ) && returnType . literalValue === true ) { return false ; } } return true ; } return false ; } } } function canBeTruthy ( type , recursionLevel = 0 ) { if ( recursionLevel > maxTypeRecursionCount ) { return true ; } switch ( type . category ) { case TypeCategory . Unknown : case TypeCategory . Function : case TypeCategory . OverloadedFunction : case TypeCategory . Module : case TypeCategory . TypeVar : case TypeCategory . Never : case TypeCategory . Any : { return true ; } case TypeCategory . Union : { return findSubtype ( type , ( subtype ) => canBeTruthy ( subtype , recursionLevel + 1 ) ) !== undefined ; } case TypeCategory . Unbound : case TypeCategory . None : { return false ; } case TypeCategory . Class : { if ( TypeBase . isInstantiable ( type ) ) { return true ; } if ( isTupleClass ( type ) ) { if ( type . tupleTypeArguments && type . tupleTypeArguments ! . length === 0 ) { return false ; } } if ( type . literalValue === false || type . literalValue === 0 || type . literalValue === '' ) { return false ; } const boolMethod = lookUpObjectMember ( type , '__bool__' ) ; if ( boolMethod ) { const boolMethodType = getTypeOfMember ( boolMethod ) ; if ( isFunction ( boolMethodType ) && boolMethodType . details . declaredReturnType ) { const returnType = boolMethodType . details . declaredReturnType ; if ( isClassInstance ( returnType ) && ClassType . isBuiltIn ( returnType , 'bool' ) && returnType . literalValue === false ) { return false ; } } } return true ; } } } function removeTruthinessFromType ( type ) { return mapSubtypes ( type , ( subtype ) => { if ( isClassInstance ( subtype ) ) { if ( subtype . literalValue !== undefined ) { return ! subtype . literalValue ? subtype : undefined ; } if ( ClassType . isBuiltIn ( subtype , 'bool' ) ) { return ClassType . cloneWithLiteral ( subtype , false ) ; } } if ( canBeFalsy ( subtype ) ) { return subtype ; } return undefined ; } ) ; } function removeFalsinessFromType ( type ) { return mapSubtypes ( type , ( subtype ) => { if ( isClassInstance ( subtype ) ) { if ( subtype . literalValue !== undefined ) { return subtype . literalValue ? subtype : undefined ; } if ( ClassType . isBuiltIn ( subtype , 'bool' ) ) { return ClassType . cloneWithLiteral ( subtype , true ) ; } } if ( canBeTruthy ( subtype ) ) { return subtype ; } return undefined ; } ) ; } function getTypeFromObjectMember ( errorNode , objectType , memberName , usage = { method : 'get' } , diag = undefined , memberAccessFlags = MemberAccessFlags . None , bindToType ? ) { const memberInfo = getTypeFromClassMemberName ( errorNode , ClassType . cloneAsInstantiable ( objectType ) , memberName , usage , diag , memberAccessFlags | MemberAccessFlags . DisallowClassVarWrites , bindToType ) ; if ( memberInfo ) { return { node : errorNode , type : memberInfo . type , isIncomplete : ! ! memberInfo . isTypeIncomplete , isAsymmetricDescriptor : memberInfo . isAsymmetricDescriptor , } ; } return undefined ; } function getTypeFromClassMember ( errorNode , classType , memberName , usage = { method : 'get' } , diag = undefined , memberAccessFlags = MemberAccessFlags . None , bindToType ? ) { let memberInfo ; if ( ClassType . isPartiallyConstructed ( classType ) ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . classDefinitionCycle ( ) . format ( { name : classType . details . name } ) , errorNode ) ; return { node : errorNode , type : UnknownType . create ( ) } ; } if ( ( memberAccessFlags & MemberAccessFlags . ConsiderMetaclassOnly ) === 0 ) { memberInfo = getTypeFromClassMemberName ( errorNode , classType , memberName , usage , diag , memberAccessFlags | MemberAccessFlags . AccessClassMembersOnly , bindToType ) ; } if ( memberInfo && ! memberInfo . isClassVar && memberInfo . classType && isClass ( memberInfo . classType ) && ClassType . isProtocolClass ( memberInfo . classType ) ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . protocolMemberNotClassVar ( ) . format ( { memberName , className : memberInfo . classType . details . name , } ) , errorNode ) ; } if ( ! memberInfo ) { const metaclass = classType . details . effectiveMetaclass ; if ( metaclass && isInstantiableClass ( metaclass ) && ! ClassType . isSameGenericClass ( metaclass , classType ) ) { memberInfo = getTypeFromClassMemberName ( errorNode , metaclass , memberName , usage , undefined , memberAccessFlags , classType ) ; } } if ( memberInfo ) { return { node : errorNode , type : memberInfo . type , isIncomplete : ! ! memberInfo . isTypeIncomplete , isAsymmetricDescriptor : memberInfo . isAsymmetricDescriptor , } ; } return undefined ; } function getBoundMethod ( classType , memberName , treatConstructorAsClassMember = false ) { const memberInfo = lookUpClassMember ( classType , memberName , ClassMemberLookupFlags . SkipInstanceVariables ) ; if ( memberInfo ) { const unboundMethodType = getTypeOfMember ( memberInfo ) ; if ( isFunction ( unboundMethodType ) || isOverloadedFunction ( unboundMethodType ) ) { const boundMethod = bindFunctionToClassOrObject ( ClassType . cloneAsInstance ( classType ) , unboundMethodType , undefined , undefined , undefined , treatConstructorAsClassMember ) ; if ( boundMethod ) { return boundMethod ; } } } return undefined ; } function getTypeAnnotationForParameter ( node , paramIndex ) { if ( paramIndex >= node . parameters . length ) { return undefined ; } const param = node . parameters [ paramIndex ] ; if ( param . typeAnnotation ) { return param . typeAnnotation ; } else if ( param . typeAnnotationComment ) { return param . typeAnnotationComment ; } if ( ! node . functionAnnotationComment || node . functionAnnotationComment . isParamListEllipsis ) { return undefined ; } let firstCommentAnnotationIndex = 0 ; const paramAnnotations = node . functionAnnotationComment . paramTypeAnnotations ; if ( paramAnnotations . length < node . parameters . length ) { firstCommentAnnotationIndex = 1 ; } const adjIndex = paramIndex - firstCommentAnnotationIndex ; if ( adjIndex < 0 || adjIndex >= paramAnnotations . length ) { return undefined ; } return paramAnnotations [ adjIndex ] ; } function getCallSignatureInfo ( callNode , activeIndex , activeOrFake ) { const exprNode = callNode . leftExpression ; const callType = getType ( exprNode ) ; if ( callType === undefined ) { return undefined ; } const argList = [ ] ; let previousCategory = ArgumentCategory . Simple ; function addFakeArg ( ) { argList . push ( { argumentCategory : previousCategory , type : UnknownType . create ( ) , active : true , } ) ; } callNode . arguments . forEach ( ( arg , index ) => { let active = false ; if ( index === activeIndex ) { if ( activeOrFake ) { active = true ; } else { addFakeArg ( ) ; } } previousCategory = arg . argumentCategory ; argList . push ( { valueExpression : arg . valueExpression , argumentCategory : arg . argumentCategory , name : arg . name , active : active , } ) ; } ) ; if ( callNode . arguments . length < activeIndex ) { addFakeArg ( ) ; } const signatures = [ ] ; function addOneFunctionToSignature ( type ) { let callResult ; useSpeculativeMode ( callNode ! , ( ) => { callResult = validateFunctionArguments ( exprNode , argList , type , new TypeVarMap ( getTypeVarScopeId ( type ) ) , true ) ; } ) ; signatures . push ( { type , activeParam : callResult ?. activeParam , } ) ; } function addFunctionToSignature ( type ) { if ( isFunction ( type ) ) { addOneFunctionToSignature ( type ) ; } else { type . overloads . forEach ( ( func ) => { if ( FunctionType . isOverloaded ( func ) ) { addOneFunctionToSignature ( func ) ; } } ) ; } } doForEachSubtype ( callType , ( subtype ) => { switch ( subtype . category ) { case TypeCategory . Function : case TypeCategory . OverloadedFunction : { addFunctionToSignature ( subtype ) ; break ; } case TypeCategory . Class : { if ( TypeBase . isInstantiable ( subtype ) ) { let methodType ; methodType = getBoundMethod ( subtype , '__init__' ) ; const isObjectInit = ! ! methodType && isFunction ( methodType ) && methodType . details . fullName === 'builtins.object.__init__' ; const isSkipConstructor = ! ! methodType && isFunction ( methodType ) && FunctionType . isSkipConstructorCheck ( methodType ) ; if ( ! methodType || isObjectInit || isSkipConstructor ) { const constructorType = getBoundMethod ( subtype , '__new__' , true ) ; if ( constructorType ) { const isObjectNew = isFunction ( constructorType ) && constructorType . details . fullName === 'builtins.object.__new__' ; if ( ! isObjectNew ) { methodType = constructorType ; } } } if ( methodType ) { addFunctionToSignature ( methodType ) ; } } else { const methodType = getBoundMethod ( subtype , '__call__' ) ; if ( methodType ) { addFunctionToSignature ( methodType ) ; } } break ; } } } ) ; if ( signatures . length === 0 ) { return undefined ; } return { callNode , signatures , } ; } function isDeclaredTypeAlias ( expression ) { if ( expression . nodeType === ParseNodeType . TypeAnnotation ) { if ( expression . valueExpression . nodeType === ParseNodeType . Name ) { const symbolWithScope = lookUpSymbolRecursive ( expression , expression . valueExpression . value , false ) ; if ( symbolWithScope ) { const symbol = symbolWithScope . symbol ; return symbol . getDeclarations ( ) . find ( ( decl ) => isExplicitTypeAliasDeclaration ( decl ) ) !== undefined ; } } } return false ; } function getDeclaredTypeForExpression ( expression , usage ? ) { let symbol ; let classOrObjectBase ; let memberAccessClass ; switch ( expression . nodeType ) { case ParseNodeType . Name : { const symbolWithScope = lookUpSymbolRecursive ( expression , expression . value , true ) ; if ( symbolWithScope ) { symbol = symbolWithScope . symbol ; if ( getDeclaredTypeOfSymbol ( symbol ) === undefined && symbolWithScope . scope . type === ScopeType . Class ) { const enclosingClass = ParseTreeUtils . getEnclosingClassOrFunction ( expression ) ; if ( enclosingClass && enclosingClass . nodeType === ParseNodeType . Class ) { const classTypeInfo = getTypeOfClass ( enclosingClass ) ; if ( classTypeInfo ) { const classMemberInfo = lookUpClassMember ( classTypeInfo . classType , expression . value , ClassMemberLookupFlags . SkipInstanceVariables | ClassMemberLookupFlags . DeclaredTypesOnly ) ; if ( classMemberInfo ) { symbol = classMemberInfo . symbol ; } } } } } break ; } case ParseNodeType . TypeAnnotation : { return getDeclaredTypeForExpression ( expression . valueExpression ) ; } case ParseNodeType . MemberAccess : { const baseType = makeTopLevelTypeVarsConcrete ( getTypeOfExpression ( expression . leftExpression , undefined , EvaluatorFlags . DoNotSpecialize ) . type ) ; let classMemberInfo ; if ( isClassInstance ( baseType ) ) { classMemberInfo = lookUpObjectMember ( baseType , expression . memberName . value , ClassMemberLookupFlags . DeclaredTypesOnly ) ; classOrObjectBase = baseType ; memberAccessClass = classMemberInfo ?. classType ; } else if ( isInstantiableClass ( baseType ) ) { classMemberInfo = lookUpClassMember ( baseType , expression . memberName . value , ClassMemberLookupFlags . SkipInstanceVariables | ClassMemberLookupFlags . DeclaredTypesOnly ) ; classOrObjectBase = baseType ; memberAccessClass = classMemberInfo ?. classType ; } if ( classMemberInfo ) { symbol = classMemberInfo . symbol ; } break ; } case ParseNodeType . Index : { const baseType = getDeclaredTypeForExpression ( expression . baseExpression ) ; if ( baseType && isClassInstance ( baseType ) ) { const setItemMember = lookUpClassMember ( baseType , '__setitem__' ) ; if ( setItemMember ) { const setItemType = getTypeOfMember ( setItemMember ) ; if ( isFunction ( setItemType ) ) { const boundFunction = bindFunctionToClassOrObject ( baseType , setItemType , isInstantiableClass ( setItemMember . classType ) ? setItemMember . classType : undefined , expression , undefined , false ) ; if ( boundFunction && isFunction ( boundFunction ) ) { if ( boundFunction . details . parameters . length === 2 ) { const paramType = FunctionType . getEffectiveParameterType ( boundFunction , 1 ) ; if ( ! isAnyOrUnknown ( paramType ) ) { return paramType ; } } } } } else if ( ClassType . isTypedDictClass ( baseType ) ) { const typeFromTypedDict = getTypeFromIndexedTypedDict ( evaluatorInterface , expression , baseType , usage || { method : 'get' } ) ; if ( typeFromTypedDict ) { return typeFromTypedDict . type ; } } } break ; } } if ( symbol ) { let declaredType = getDeclaredTypeOfSymbol ( symbol ) ; if ( declaredType ) { if ( isProperty ( declaredType ) ) { const setterInfo = lookUpClassMember ( declaredType as ClassType , 'fset' ) ; const setter = setterInfo ? getTypeOfMember ( setterInfo ) : undefined ; if ( ! setter || ! isFunction ( setter ) || setter . details . parameters . length < 2 ) { return undefined ; } declaredType = setter . details . parameters [ 1 ] . type ; } if ( classOrObjectBase ) { if ( memberAccessClass && isInstantiableClass ( memberAccessClass ) ) { declaredType = partiallySpecializeType ( declaredType , memberAccessClass ) ; } if ( isFunction ( declaredType ) || isOverloadedFunction ( declaredType ) ) { declaredType = bindFunctionToClassOrObject ( classOrObjectBase , declaredType , undefined , expression ) ; } } return declaredType ; } } return undefined ; } function getTypeFromAwaitable ( type , errorNode ? ) { return mapSubtypes ( type , ( subtype ) => { if ( isAnyOrUnknown ( subtype ) ) { return subtype ; } const generatorReturnType = getReturnTypeFromGenerator ( subtype ) ; if ( generatorReturnType ) { return generatorReturnType ; } if ( isClassInstance ( subtype ) ) { const awaitReturnType = getSpecializedReturnType ( subtype , '__await__' , errorNode ) ; if ( awaitReturnType ) { if ( isAnyOrUnknown ( awaitReturnType ) ) { return awaitReturnType ; } if ( isClassInstance ( awaitReturnType ) ) { const iterReturnType = getSpecializedReturnType ( awaitReturnType , '__iter__' , errorNode ) ; if ( iterReturnType ) { const generatorReturnType = getReturnTypeFromGenerator ( awaitReturnType ) ; if ( generatorReturnType ) { return generatorReturnType ; } } } } } if ( errorNode ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( errorNode ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeNotAwaitable ( ) . format ( { type : printType ( subtype ) } ) , errorNode ) ; } return UnknownType . create ( ) ; } ) ; } function getTypeFromIterator ( type , isAsync , errorNode ) { const iterMethodName = isAsync ? '__aiter__' : '__iter__' ; const nextMethodName = isAsync ? '__anext__' : '__next__' ; let isValidIterator = true ; type = makeTopLevelTypeVarsConcrete ( type ) ; if ( isOptionalType ( type ) ) { if ( errorNode ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportOptionalIterable , DiagnosticRule . reportOptionalIterable , Localizer . Diagnostic . noneNotIterable ( ) , errorNode ) ; } type = removeNoneFromUnion ( type ) ; } const iterableType = mapSubtypes ( type , ( subtype ) => { subtype = makeTopLevelTypeVarsConcrete ( subtype ) ; if ( isAnyOrUnknown ( subtype ) ) { return subtype ; } const diag = new DiagnosticAddendum ( ) ; if ( isClass ( subtype ) ) { let iterReturnType ; if ( TypeBase . isInstance ( subtype ) ) { if ( isTupleClass ( subtype ) && subtype . tupleTypeArguments && subtype . tupleTypeArguments . length === 0 ) { return NeverType . create ( ) ; } iterReturnType = getSpecializedReturnType ( subtype , iterMethodName , errorNode ) ; } else if ( TypeBase . isInstantiable ( subtype ) && subtype . details . effectiveMetaclass && isInstantiableClass ( subtype . details . effectiveMetaclass ) ) { iterReturnType = getSpecializedReturnType ( ClassType . cloneAsInstance ( subtype . details . effectiveMetaclass ) , iterMethodName , errorNode , subtype ) ; } if ( ! iterReturnType ) { if ( isClassInstance ( subtype ) ) { const getItemReturnType = getSpecializedReturnType ( subtype , '__getitem__' , errorNode ) ; if ( getItemReturnType ) { return getItemReturnType ; } } diag . addMessage ( Localizer . Diagnostic . methodNotDefined ( ) . format ( { name : iterMethodName } ) ) ; } else { const iterReturnTypeDiag = new DiagnosticAddendum ( ) ; const returnType = mapSubtypesExpandTypeVars ( iterReturnType , undefined , ( subtype ) => { if ( isAnyOrUnknown ( subtype ) ) { return subtype ; } if ( isClassInstance ( subtype ) ) { const nextReturnType = getSpecializedReturnType ( subtype , nextMethodName , errorNode ) ; if ( ! nextReturnType ) { iterReturnTypeDiag . addMessage ( Localizer . Diagnostic . methodNotDefinedOnType ( ) . format ( { name : nextMethodName , type : printType ( subtype ! ) , } ) ) ; } else { if ( ! isAsync ) { return nextReturnType ; } return getTypeFromAwaitable ( nextReturnType , errorNode ) ; } } else { iterReturnTypeDiag . addMessage ( Localizer . Diagnostic . methodReturnsNonObject ( ) . format ( { name : iterMethodName } ) ) ; } return undefined ; } ) ; if ( iterReturnTypeDiag . isEmpty ( ) ) { return returnType ; } diag . addAddendum ( iterReturnTypeDiag ) ; } } if ( errorNode ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeNotIterable ( ) . format ( { type : printType ( subtype ) } ) + diag . getString ( ) , errorNode ) ; } isValidIterator = false ; return undefined ; } ) ; return isValidIterator ? iterableType : undefined ; } function getTypeFromIterable ( type , isAsync , errorNode ) { const iterMethodName = isAsync ? '__aiter__' : '__iter__' ; let isValidIterable = true ; type = makeTopLevelTypeVarsConcrete ( type ) ; if ( isOptionalType ( type ) ) { if ( errorNode ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportOptionalIterable , DiagnosticRule . reportOptionalIterable , Localizer . Diagnostic . noneNotIterable ( ) , errorNode ) ; } type = removeNoneFromUnion ( type ) ; } const iterableType = mapSubtypes ( type , ( subtype ) => { if ( isAnyOrUnknown ( subtype ) ) { return subtype ; } if ( isClass ( subtype ) ) { let iterReturnType ; if ( TypeBase . isInstance ( subtype ) ) { iterReturnType = getSpecializedReturnType ( subtype , iterMethodName , errorNode ) ; } else if ( TypeBase . isInstantiable ( subtype ) && subtype . details . effectiveMetaclass && isInstantiableClass ( subtype . details . effectiveMetaclass ) ) { iterReturnType = getSpecializedReturnType ( ClassType . cloneAsInstance ( subtype . details . effectiveMetaclass ) , iterMethodName , errorNode , subtype ) ; } if ( iterReturnType ) { return makeTopLevelTypeVarsConcrete ( iterReturnType ) ; } } if ( errorNode ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeNotIterable ( ) . format ( { type : printType ( subtype ) } ) , errorNode ) ; } isValidIterable = false ; return undefined ; } ) ; return isValidIterable ? iterableType : undefined ; } function getTypingType ( node , symbolName ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; return getTypeFromTypeshedModule ( symbolName , fileInfo . typingModulePath ) ; } function getTypeshedType ( node , symbolName ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; return getTypeFromTypeshedModule ( symbolName , fileInfo . typeshedModulePath ) ; } function getTypeFromTypeshedModule ( symbolName , importPath ) { if ( ! importPath ) { return undefined ; } const lookupResult = importLookup ( importPath ) ; if ( ! lookupResult ) { return undefined ; } const symbol = lookupResult . symbolTable . get ( symbolName ) ; if ( ! symbol ) { return undefined ; } return getEffectiveTypeOfSymbol ( symbol ) ; } function isNodeReachable ( node , sourceNode ? ) { const flowNode = AnalyzerNodeInfo . getFlowNode ( node ) ; if ( ! flowNode ) { if ( node . parent ) { return isNodeReachable ( node . parent , sourceNode ) ; } return false ; } const sourceFlowNode = sourceNode ? AnalyzerNodeInfo . getFlowNode ( sourceNode ) : undefined ; if ( ! codeFlowEngine . isFlowNodeReachable ( flowNode , sourceFlowNode ) ) { return false ; } return true ; } function isAfterNodeReachable ( node ) { const returnFlowNode = AnalyzerNodeInfo . getAfterFlowNode ( node ) ; if ( ! returnFlowNode ) { return false ; } if ( ! codeFlowEngine . isFlowNodeReachable ( returnFlowNode ) ) { return false ; } if ( ! isFlowNodeReachableUsingNeverNarrowing ( node , returnFlowNode ) ) { return false ; } return true ; } function isFlowNodeReachableUsingNeverNarrowing ( node , flowNode ) { const analyzer = getCodeFlowAnalyzerForNode ( node . id ) ; const codeFlowResult = getTypeFromCodeFlow ( analyzer , flowNode , undefined , undefined , UnboundType . create ( ) , false ) ; return codeFlowResult . type !== undefined ; } function isFlowPathBetweenNodes ( sourceNode , sinkNode ) { const sourceFlowNode = AnalyzerNodeInfo . getFlowNode ( sourceNode ) ; const sinkFlowNode = AnalyzerNodeInfo . getFlowNode ( sinkNode ) ; if ( ! sourceFlowNode || ! sinkFlowNode ) { return false ; } if ( sourceFlowNode === sinkFlowNode ) { return true ; } return codeFlowEngine . isFlowNodeReachable ( sinkFlowNode , sourceFlowNode ) ; } function isAnnotationLiteralValue ( node ) { if ( node . parent && node . parent . nodeType === ParseNodeType . Index ) { const baseType = getTypeOfExpression ( node . parent . baseExpression ) . type ; if ( baseType && isInstantiableClass ( baseType ) ) { if ( ClassType . isSpecialBuiltIn ( baseType , 'Literal' ) ) { return true ; } } } return false ; } function addInformation ( message , node , range ? ) { return addDiagnosticWithSuppressionCheck ( 'information' , message , node , range ) ; } function addWarning ( message , node , range ? ) { return addDiagnosticWithSuppressionCheck ( 'warning' , message , node , range ) ; } function addError ( message , node , range ? ) { return addDiagnosticWithSuppressionCheck ( 'error' , message , node , range ) ; } function addUnusedCode ( node , textRange ) { if ( ! isDiagnosticSuppressedForNode ( node ) ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; fileInfo . diagnosticSink . addUnusedCodeWithTextRange ( Localizer . Diagnostic . unreachableCode ( ) , textRange ) ; } } function addDeprecated ( message , node ) { if ( ! isDiagnosticSuppressedForNode ( node ) ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; fileInfo . diagnosticSink . addDeprecatedWithTextRange ( message , node ) ; } } function addDiagnosticWithSuppressionCheck ( diagLevel , message , node , range ? ) { if ( ! isDiagnosticSuppressedForNode ( node ) ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; return fileInfo . diagnosticSink . addDiagnosticWithTextRange ( diagLevel , message , range || node ) ; } return undefined ; } function isDiagnosticSuppressedForNode ( node ) { return ( suppressedNodeStack . some ( ( suppressedNode ) => ParseTreeUtils . isNodeContainedWithin ( node , suppressedNode ) ) || speculativeTypeTracker . isSpeculative ( node ) || incompleteTypeTracker . isUndoTrackingEnabled ( ) ) ; } function addDiagnostic ( diagLevel , rule , message , node ) { if ( diagLevel === 'none' ) { return undefined ; } const diagnostic = addDiagnosticWithSuppressionCheck ( diagLevel , message , node ) ; if ( diagnostic ) { diagnostic . setRule ( rule ) ; } return diagnostic ; } function addDiagnosticForTextRange ( fileInfo , diagLevel , rule , message , range ) { if ( diagLevel === 'none' ) { return undefined ; } const diagnostic = fileInfo . diagnosticSink . addDiagnosticWithTextRange ( diagLevel , message , range ) ; if ( rule ) { diagnostic . setRule ( rule ) ; } return diagnostic ; } function addExpectedClassDiagnostic ( type , node ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; const diag = new DiagnosticAddendum ( ) ; if ( isUnion ( type ) ) { doForEachSubtype ( type , ( subtype ) => { if ( ! TypeBase . isInstantiable ( subtype ) ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeNotClass ( ) . format ( { type : printType ( subtype ) } ) ) ; } } ) ; } addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeExpectedClass ( ) . format ( { type : printType ( type ) } ) + diag . getString ( ) , node ) ; } function assignTypeToNameNode ( nameNode , type , isTypeIncomplete , srcExpression ? , expectedTypeDiagAddendum ? ) { const nameValue = nameNode . value ; const symbolWithScope = lookUpSymbolRecursive ( nameNode , nameValue , false ) ; if ( ! symbolWithScope ) { return ; } const declarations = symbolWithScope . symbol . getDeclarations ( ) ; let declaredType = getDeclaredTypeOfSymbol ( symbolWithScope . symbol ) ; const fileInfo = AnalyzerNodeInfo . getFileInfo ( nameNode ) ; if ( declaredType === undefined && symbolWithScope . scope . type === ScopeType . Class ) { const containingClass = ParseTreeUtils . getEnclosingClass ( nameNode ) ; if ( containingClass ) { const classType = getTypeOfClass ( containingClass ) ; if ( classType ) { const memberInfo = lookUpClassMember ( classType . classType , nameNode . value , ClassMemberLookupFlags . SkipOriginalClass ) ; if ( memberInfo ?. isTypeDeclared ) { declaredType = getTypeOfMember ( memberInfo ) ; } } } } let destType = type ; if ( declaredType && srcExpression ) { let diagAddendum = new DiagnosticAddendum ( ) ; if ( ! canAssignType ( declaredType , type , diagAddendum ) ) { if ( expectedTypeDiagAddendum ) { diagAddendum = expectedTypeDiagAddendum ; } addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeAssignmentMismatch ( ) . format ( { sourceType : printType ( type ) , destType : printType ( declaredType ) , } ) + diagAddendum . getString ( ) , srcExpression || nameNode ) ; destType = declaredType ; } else { destType = narrowTypeBasedOnAssignment ( declaredType , type ) ; } } else { const scope = ScopeUtils . getScopeForNode ( nameNode ) ; if ( scope ?. type === ScopeType . Class ) { if ( TypeBase . isInstance ( destType ) && ! isConstantName ( nameValue ) && ! isFinalVariable ( symbolWithScope . symbol ) ) { destType = stripLiteralValue ( destType ) ; } } } const varDecl = declarations . find ( ( decl ) => decl . type === DeclarationType . Variable ) ; if ( varDecl && varDecl . type === DeclarationType . Variable && srcExpression ) { if ( varDecl . isConstant ) { if ( nameNode !== declarations [ 0 ] . node ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportConstantRedefinition , DiagnosticRule . reportConstantRedefinition , Localizer . Diagnostic . constantRedefinition ( ) . format ( { name : nameValue } ) , nameNode ) ; } } } writeTypeCache ( nameNode , destType , EvaluatorFlags . None , isTypeIncomplete , undefined , false ) ; } function assignTypeToMemberAccessNode ( target , type , isTypeIncomplete , srcExpr ? , expectedTypeDiagAddendum ? ) { const baseTypeResult = getTypeOfExpression ( target . leftExpression , undefined , EvaluatorFlags . DoNotSpecialize ) ; const baseType = makeTopLevelTypeVarsConcrete ( baseTypeResult . type ) ; if ( target . leftExpression . nodeType === ParseNodeType . Name ) { const enclosingClassNode = ParseTreeUtils . getEnclosingClass ( target ) ; if ( enclosingClassNode ) { const classTypeResults = getTypeOfClass ( enclosingClassNode ) ; if ( classTypeResults && isInstantiableClass ( classTypeResults . classType ) ) { if ( isClassInstance ( baseType ) ) { if ( ClassType . isSameGenericClass ( baseType , classTypeResults . classType ) ) { assignTypeToMemberVariable ( target , type , isTypeIncomplete , true , srcExpr ) ; } } else if ( isInstantiableClass ( baseType ) ) { if ( ClassType . isSameGenericClass ( baseType , classTypeResults . classType ) ) { assignTypeToMemberVariable ( target , type , isTypeIncomplete , false , srcExpr ) ; } } if ( ClassType . isProtocolClass ( classTypeResults . classType ) ) { const memberSymbol = classTypeResults . classType . details . fields . get ( target . memberName . value ) ; if ( memberSymbol ) { const classLevelDecls = memberSymbol . getDeclarations ( ) . filter ( ( decl ) => { return ! ParseTreeUtils . getEnclosingFunction ( decl . node ) ; } ) ; if ( classLevelDecls . length === 0 ) { addError ( Localizer . Diagnostic . assignmentInProtocol ( ) , target . memberName ) ; } } } } } } const setTypeResult = getTypeFromMemberAccessWithBaseType ( target , baseTypeResult , { method : 'set' , setType : type , setErrorNode : srcExpr , setExpectedTypeDiag : expectedTypeDiagAddendum } , EvaluatorFlags . None ) ; if ( setTypeResult . isAsymmetricDescriptor ) { setAsymmetricDescriptorAssignment ( target ) ; } writeTypeCache ( target . memberName , type , EvaluatorFlags . None , isTypeIncomplete , undefined , false ) ; writeTypeCache ( target , type , EvaluatorFlags . None , isTypeIncomplete , undefined , false ) ; } function assignTypeToMemberVariable ( node , srcType , isTypeIncomplete , isInstanceMember , srcExprNode ? ) { const memberName = node . memberName . value ; const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; const classDef = ParseTreeUtils . getEnclosingClass ( node ) ; if ( ! classDef ) { return ; } const classTypeInfo = getTypeOfClass ( classDef ) ; if ( classTypeInfo && isInstantiableClass ( classTypeInfo . classType ) ) { let memberInfo = lookUpClassMember ( classTypeInfo . classType , memberName , isInstanceMember ? ClassMemberLookupFlags . Default : ClassMemberLookupFlags . SkipInstanceVariables ) ; const memberFields = classTypeInfo . classType . details . fields ; if ( memberInfo ) { const memberClass = isInstantiableClass ( memberInfo . classType ) ? memberInfo . classType : undefined ; const isThisClass = memberClass && ClassType . isSameGenericClass ( classTypeInfo . classType , memberClass ) ; if ( isThisClass && isInstanceMember ) { if ( memberClass ?. details . inheritedSlotsNames && memberClass ?. details . localSlotsNames ) { if ( memberClass . details . localSlotsNames . length > 0 && ! memberClass . details . inheritedSlotsNames . some ( ( name ) => name === memberName ) ) { const declaredType = getDeclaredTypeOfSymbol ( memberInfo . symbol ) ; if ( ! declaredType || ! isProperty ( declaredType ) ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . slotsAttributeError ( ) . format ( { name : memberName } ) , node . memberName ) ; } } } } if ( isThisClass && memberInfo . isInstanceMember === isInstanceMember ) { const symbol = memberFields . get ( memberName ) ! ; assert ( symbol !== undefined ) ; const typedDecls = symbol . getDeclarations ( ) ; if ( typedDecls . length > 0 && typedDecls [ 0 ] . type === DeclarationType . Variable && srcExprNode && node . memberName !== typedDecls [ 0 ] . node ) { if ( typedDecls [ 0 ] . isConstant ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportConstantRedefinition , DiagnosticRule . reportConstantRedefinition , Localizer . Diagnostic . constantRedefinition ( ) . format ( { name : node . memberName . value } ) , node . memberName ) ; } } } else { const declaredType = getDeclaredTypeOfSymbol ( memberInfo . symbol ) ; if ( declaredType && ! isProperty ( declaredType ) ) { if ( ! memberInfo . isInstanceMember && isInstanceMember ) { setSymbolAccessed ( fileInfo , memberInfo . symbol , node . memberName ) ; const memberType = getTypeOfMember ( memberInfo ) ; srcType = combineTypes ( [ srcType , memberType ] ) ; } } } } memberInfo = lookUpClassMember ( classTypeInfo . classType , memberName , ClassMemberLookupFlags . DeclaredTypesOnly ) ; if ( ! memberInfo && srcExprNode && ! isTypeIncomplete ) { reportPossibleUnknownAssignment ( fileInfo . diagnosticRuleSet . reportUnknownMemberType , DiagnosticRule . reportUnknownMemberType , node . memberName , srcType , node , true ) ; } } } function assignTypeToTupleNode ( target , type , isTypeIncomplete , srcExpr ) { const targetTypes = new Array ( target . expressions . length ) ; for ( let i = 0 ; i < target . expressions . length ; i ++ ) { targetTypes [ i ] = [ ] ; } const unpackIndex = target . expressions . findIndex ( ( expr ) => expr . nodeType === ParseNodeType . Unpack ) ; type = makeTopLevelTypeVarsConcrete ( type ) ; const diagAddendum = new DiagnosticAddendum ( ) ; doForEachSubtype ( type , ( subtype ) => { const tupleType = getSpecializedTupleType ( subtype ) ; if ( tupleType && tupleType . tupleTypeArguments ) { const sourceEntryTypes = tupleType . tupleTypeArguments ; const sourceEntryCount = sourceEntryTypes . length ; if ( isOpenEndedTupleClass ( tupleType ) ) { for ( let index = 0 ; index < target . expressions . length ; index ++ ) { targetTypes [ index ] . push ( addConditionToType ( sourceEntryTypes [ 0 ] , getTypeCondition ( subtype ) ) ) ; } } else { let sourceIndex = 0 ; let targetIndex = 0 ; for ( targetIndex = 0 ; targetIndex < target . expressions . length ; targetIndex ++ ) { if ( targetIndex === unpackIndex ) { const remainingTargetEntries = target . expressions . length - targetIndex - 1 ; const remainingSourceEntries = sourceEntryCount - sourceIndex ; let entriesToPack = Math . max ( remainingSourceEntries - remainingTargetEntries , 0 ) ; while ( entriesToPack > 0 ) { targetTypes [ targetIndex ] . push ( addConditionToType ( sourceEntryTypes [ sourceIndex ] , getTypeCondition ( subtype ) ) ) ; sourceIndex ++ ; entriesToPack -- ; } } else { if ( sourceIndex >= sourceEntryCount ) { break ; } targetTypes [ targetIndex ] . push ( addConditionToType ( sourceEntryTypes [ sourceIndex ] , getTypeCondition ( subtype ) ) ) ; sourceIndex ++ ; } } if ( targetIndex < target . expressions . length || sourceIndex < sourceEntryCount ) { const expectedEntryCount = unpackIndex >= 0 ? target . expressions . length - 1 : target . expressions . length ; const subDiag = diagAddendum . createAddendum ( ) ; subDiag . addMessage ( Localizer . DiagnosticAddendum . tupleAssignmentMismatch ( ) . format ( { type : printType ( subtype ) , } ) ) ; subDiag . createAddendum ( ) . addMessage ( Localizer . DiagnosticAddendum . tupleSizeMismatch ( ) . format ( { expected : expectedEntryCount , received : sourceEntryCount , } ) ) ; } } } else { const iterableType = getTypeFromIterator ( subtype , false , srcExpr ) || UnknownType . create ( ) ; for ( let index = 0 ; index < target . expressions . length ; index ++ ) { targetTypes [ index ] . push ( addConditionToType ( iterableType , getTypeCondition ( subtype ) ) ) ; } } } ) ; if ( ! diagAddendum . isEmpty ( ) ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( target ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . tupleAssignmentMismatch ( ) . format ( { type : printType ( type ) , } ) + diagAddendum . getString ( ) , target ) ; } target . expressions . forEach ( ( expr , index ) => { const typeList = targetTypes [ index ] ; let targetType = typeList . length === 0 ? UnknownType . create ( ) : combineTypes ( typeList ) ; targetType = removeNoReturnFromUnion ( targetType ) ; assignTypeToExpression ( expr , targetType , isTypeIncomplete , srcExpr , true ) ; } ) ; writeTypeCache ( target , type , EvaluatorFlags . None , isTypeIncomplete ) ; } function makeTopLevelTypeVarsConcrete ( type , conditionFilter ? ) { return mapSubtypes ( type , ( subtype ) => { if ( isParamSpec ( subtype ) ) { if ( subtype . paramSpecAccess === 'args' ) { if ( tupleClassType && isInstantiableClass ( tupleClassType ) && objectType && isClassInstance ( objectType ) ) { return ClassType . cloneAsInstance ( specializeTupleClass ( tupleClassType , [ objectType , AnyType . create ( true ) ] ) ) ; } return UnknownType . create ( ) ; } else if ( subtype . paramSpecAccess === 'kwargs' ) { if ( dictClassType && isInstantiableClass ( dictClassType ) && strClassType && isInstantiableClass ( strClassType ) && objectType && isClassInstance ( objectType ) ) { return ClassType . cloneAsInstance ( ClassType . cloneForSpecialization ( dictClassType , [ convertToInstance ( strClassType ) , objectType ] , true ) ) ; } return UnknownType . create ( ) ; } } if ( isTypeVar ( subtype ) && ! subtype . details . recursiveTypeAliasName ) { if ( subtype . details . boundType ) { const boundType = TypeBase . isInstantiable ( subtype ) ? convertToInstantiable ( subtype . details . boundType ) : subtype . details . boundType ; return subtype . details . isSynthesized ? boundType : addConditionToType ( boundType , [ { typeVarName : TypeVarType . getNameWithScope ( subtype ) , constraintIndex : 0 , isConstrainedTypeVar : false , } , ] ) ; } if ( subtype . details . recursiveTypeAliasName ) { return subtype ; } if ( subtype . details . constraints . length > 0 ) { const typesToCombine = [ ] ; subtype . details . constraints . forEach ( ( constraintType , constraintIndex ) => { if ( conditionFilter ) { const typeVarName = TypeVarType . getNameWithScope ( subtype ) ; const applicableConstraint = conditionFilter . find ( ( filter ) => filter . typeVarName === typeVarName ) ; if ( applicableConstraint && applicableConstraint . constraintIndex !== constraintIndex ) { return ; } } if ( TypeBase . isInstantiable ( subtype ) ) { constraintType = convertToInstantiable ( constraintType ) ; } typesToCombine . push ( addConditionToType ( constraintType , [ { typeVarName : TypeVarType . getNameWithScope ( subtype ) , constraintIndex , isConstrainedTypeVar : true , } , ] ) ) ; } ) ; return combineTypes ( typesToCombine ) ; } if ( subtype . details . isExemptFromBoundCheck ) { return AnyType . create ( ) ; } if ( TypeBase . isInstantiable ( subtype ) ) { if ( typeClassType && isInstantiableClass ( typeClassType ) ) { return subtype . details . isSynthesized ? typeClassType : addConditionToType ( ClassType . cloneAsInstance ( typeClassType ) , [ { typeVarName : TypeVarType . getNameWithScope ( subtype ) , constraintIndex : 0 , isConstrainedTypeVar : false , } , ] ) ; } } else if ( objectType ) { return subtype . details . isSynthesized ? objectType : addConditionToType ( objectType , [ { typeVarName : TypeVarType . getNameWithScope ( subtype ) , constraintIndex : 0 , isConstrainedTypeVar : false , } , ] ) ; } return AnyType . create ( ) ; } return subtype ; } ) ; } function mapSubtypesExpandTypeVars ( type , conditionFilter , callback ) { const newSubtypes = [ ] ; let typeChanged = false ; const expandSubtype = ( unexpandedType ) => { const expandedType = isUnion ( unexpandedType ) ? unexpandedType : makeTopLevelTypeVarsConcrete ( unexpandedType ) ; doForEachSubtype ( expandedType , ( subtype ) => { if ( conditionFilter ) { if ( ! TypeCondition . isCompatible ( getTypeCondition ( subtype ) , conditionFilter ) ) { return undefined ; } } let transformedType = callback ( subtype , unexpandedType ) ; if ( transformedType !== unexpandedType ) { typeChanged = true ; } if ( transformedType ) { const typeCondition = getTypeCondition ( subtype ) ?. filter ( ( condition ) => condition . isConstrainedTypeVar ) ; if ( typeCondition && typeCondition . length > 0 ) { transformedType = addConditionToType ( transformedType , typeCondition ) ; } newSubtypes . push ( transformedType ) ; } return undefined ; } ) ; } ; if ( isUnion ( type ) ) { type . subtypes . forEach ( ( subtype ) => { expandSubtype ( subtype ) ; } ) ; } else { expandSubtype ( type ) ; } if ( ! typeChanged ) { return type ; } const newType = combineTypes ( newSubtypes ) ; if ( newType . category === TypeCategory . Union ) { UnionType . addTypeAliasSource ( newType , type ) ; } return newType ; } function markNamesAccessed ( node , names ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; const scope = ScopeUtils . getScopeForNode ( node ) ; if ( scope ) { names . forEach ( ( symbolName ) => { const symbolInScope = scope . lookUpSymbolRecursive ( symbolName ) ; if ( symbolInScope ) { setSymbolAccessed ( fileInfo , symbolInScope . symbol , node ) ; } } ) ; } } function assignTypeToExpression ( target , type , isTypeIncomplete , srcExpr , ignoreEmptyContainers = false , expectedTypeDiagAddendum ? ) { if ( isTypeVar ( type ) ) { if ( srcExpr && srcExpr . nodeType === ParseNodeType . Call ) { const callType = getTypeOfExpression ( srcExpr . leftExpression , undefined , EvaluatorFlags . DoNotSpecialize ) . type ; if ( isInstantiableClass ( callType ) && ( ClassType . isBuiltIn ( callType , 'TypeVar' ) || ClassType . isBuiltIn ( callType , 'TypeVarTuple' ) || ClassType . isBuiltIn ( callType , 'ParamSpec' ) ) ) { if ( target . nodeType !== ParseNodeType . Name || target . value !== type . details . name ) { addError ( type . details . isParamSpec ? Localizer . Diagnostic . paramSpecAssignedName ( ) . format ( { name : TypeVarType . getReadableName ( type ) , } ) : Localizer . Diagnostic . typeVarAssignedName ( ) . format ( { name : TypeVarType . getReadableName ( type ) , } ) , target ) ; } } } } type = removeUnbound ( type ) ; switch ( target . nodeType ) { case ParseNodeType . Name : { if ( ! isTypeIncomplete ) { reportPossibleUnknownAssignment ( AnalyzerNodeInfo . getFileInfo ( target ) . diagnosticRuleSet . reportUnknownVariableType , DiagnosticRule . reportUnknownVariableType , target , type , target , ignoreEmptyContainers ) ; } assignTypeToNameNode ( target , type , isTypeIncomplete , srcExpr , expectedTypeDiagAddendum ) ; break ; } case ParseNodeType . MemberAccess : { assignTypeToMemberAccessNode ( target , type , isTypeIncomplete , srcExpr , expectedTypeDiagAddendum ) ; break ; } case ParseNodeType . Index : { const baseTypeResult = getTypeOfExpression ( target . baseExpression , undefined , EvaluatorFlags . DoNotSpecialize ) ; getTypeFromIndexWithBaseType ( target , baseTypeResult . type , { method : 'set' , setType : type , setErrorNode : srcExpr , setExpectedTypeDiag : expectedTypeDiagAddendum , } , EvaluatorFlags . None ) ; writeTypeCache ( target , type , EvaluatorFlags . None , isTypeIncomplete ) ; break ; } case ParseNodeType . Tuple : { assignTypeToTupleNode ( target , type , isTypeIncomplete , srcExpr ) ; break ; } case ParseNodeType . TypeAnnotation : { const annotationType = getTypeOfAnnotation ( target . typeAnnotation , { isVariableAnnotation : true , allowFinal : ParseTreeUtils . isFinalAllowedForAssignmentTarget ( target . valueExpression ) , allowClassVar : ParseTreeUtils . isClassVarAllowedForAssignmentTarget ( target . valueExpression ) , } ) ; const isBareFinalOrClassVar = isClassInstance ( annotationType ) && ( ClassType . isBuiltIn ( annotationType , 'Final' ) || ClassType . isBuiltIn ( annotationType , 'ClassVar' ) ) ; if ( ! isBareFinalOrClassVar ) { const isTypeAliasAnnotation = isClassInstance ( annotationType ) && ClassType . isBuiltIn ( annotationType , 'TypeAlias' ) ; if ( ! isTypeAliasAnnotation ) { if ( canAssignType ( annotationType , type ) ) { if ( ! isClassInstance ( type ) || ! ClassType . isEnumClass ( type ) ) { type = narrowTypeBasedOnAssignment ( annotationType , type ) ; } } } } assignTypeToExpression ( target . valueExpression , type , false , srcExpr , ignoreEmptyContainers , expectedTypeDiagAddendum ) ; break ; } case ParseNodeType . Unpack : { if ( target . expression . nodeType === ParseNodeType . Name ) { assignTypeToNameNode ( target . expression , getBuiltInObject ( target . expression , 'list' , [ type ] ) , false , srcExpr ) ; } break ; } case ParseNodeType . List : { const iteratedType = getTypeFromIterator ( type , false , srcExpr ) || UnknownType . create ( ) ; target . entries . forEach ( ( entry ) => { assignTypeToExpression ( entry , iteratedType , false , srcExpr , ignoreEmptyContainers ) ; } ) ; break ; } case ParseNodeType . Error : { if ( target . child ) { suppressDiagnostics ( target . child , ( ) => { getTypeOfExpression ( target . child ! ) ; } ) ; } break ; } default : { addError ( Localizer . Diagnostic . assignmentTargetExpr ( ) , target ) ; break ; } } } function verifyRaiseExceptionType ( node ) { const baseExceptionType = getBuiltInType ( node , 'BaseException' ) ; if ( node . typeExpression ) { const exceptionType = getTypeOfExpression ( node . typeExpression ) . type ; if ( exceptionType && baseExceptionType && isInstantiableClass ( baseExceptionType ) ) { const diagAddendum = new DiagnosticAddendum ( ) ; doForEachSubtype ( exceptionType , ( subtype ) => { const concreteSubtype = makeTopLevelTypeVarsConcrete ( subtype ) ; if ( ! isAnyOrUnknown ( concreteSubtype ) ) { if ( isInstantiableClass ( concreteSubtype ) && concreteSubtype . literalValue === undefined ) { if ( ! derivesFromClassRecursive ( concreteSubtype , baseExceptionType , false ) ) { diagAddendum . addMessage ( Localizer . Diagnostic . exceptionTypeIncorrect ( ) . format ( { type : printType ( subtype , false ) , } ) ) ; } else { let callResult ; suppressDiagnostics ( node . typeExpression ! , ( ) => { callResult = validateConstructorArguments ( node . typeExpression ! , [ ] , concreteSubtype , false , undefined ) ; } ) ; if ( callResult && callResult . argumentErrors ) { diagAddendum . addMessage ( Localizer . Diagnostic . exceptionTypeNotInstantiable ( ) . format ( { type : printType ( subtype , false ) , } ) ) ; } } } else if ( isClassInstance ( concreteSubtype ) ) { if ( ! derivesFromClassRecursive ( ClassType . cloneAsInstantiable ( concreteSubtype ) , baseExceptionType , false ) ) { diagAddendum . addMessage ( Localizer . Diagnostic . exceptionTypeIncorrect ( ) . format ( { type : printType ( subtype , false ) , } ) ) ; } } else { diagAddendum . addMessage ( Localizer . Diagnostic . exceptionTypeIncorrect ( ) . format ( { type : printType ( subtype , false ) , } ) ) ; } } } ) ; if ( ! diagAddendum . isEmpty ( ) ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . expectedExceptionClass ( ) + diagAddendum . getString ( ) , node . typeExpression ) ; } } } } function verifyDeleteExpression ( node ) { switch ( node . nodeType ) { case ParseNodeType . Name : { getTypeOfExpression ( node ) ; break ; } case ParseNodeType . MemberAccess : { const baseTypeResult = getTypeOfExpression ( node . leftExpression ) ; const memberType = getTypeFromMemberAccessWithBaseType ( node , baseTypeResult , { method : 'del' } , EvaluatorFlags . None ) ; writeTypeCache ( node . memberName , memberType . type , EvaluatorFlags . None , false ) ; writeTypeCache ( node , memberType . type , EvaluatorFlags . None , false ) ; break ; } case ParseNodeType . Index : { const baseTypeResult = getTypeOfExpression ( node . baseExpression , undefined , EvaluatorFlags . DoNotSpecialize ) ; getTypeFromIndexWithBaseType ( node , baseTypeResult . type , { method : 'del' } , EvaluatorFlags . None ) ; writeTypeCache ( node , UnboundType . create ( ) , EvaluatorFlags . None , false ) ; break ; } case ParseNodeType . Tuple : { node . expressions . forEach ( ( expr ) => { verifyDeleteExpression ( expr ) ; } ) ; break ; } case ParseNodeType . Error : { if ( node . child ) { suppressDiagnostics ( node . child , ( ) => { getTypeOfExpression ( node . child ! , undefined ) ; } ) ; } break ; } default : { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . delTargetExpr ( ) , node ) ; break ; } } } function setSymbolAccessed ( fileInfo , symbol , node ) { if ( ! speculativeTypeTracker . isSpeculative ( node ) && ! incompleteTypeTracker . isUndoTrackingEnabled ( ) ) { fileInfo . accessedSymbolMap . set ( symbol . id , true ) ; } } function getReturnTypeFromGenerator ( type ) { if ( isAnyOrUnknown ( type ) ) { return type ; } if ( isClassInstance ( type ) ) { if ( ClassType . isBuiltIn ( type , 'Generator' ) ) { const typeArgs = type . typeArguments ; if ( typeArgs && typeArgs . length >= 3 ) { return typeArgs [ 2 ] ; } } } return undefined ; } function getSpecializedReturnType ( objType , memberName , errorNode , bindToClass ? ) { const classMember = lookUpObjectMember ( objType , memberName , ClassMemberLookupFlags . SkipInstanceVariables ) ; if ( ! classMember ) { return undefined ; } const memberType = getTypeOfMember ( classMember ) ; if ( isAnyOrUnknown ( memberType ) ) { return memberType ; } if ( isFunction ( memberType ) ) { const methodType = bindFunctionToClassOrObject ( bindToClass || objType , memberType , classMember && isInstantiableClass ( classMember . classType ) ? classMember . classType : undefined , errorNode , undefined , false , bindToClass ) ; if ( methodType ) { return getFunctionEffectiveReturnType ( methodType as FunctionType ) ; } } return undefined ; } function getTypeFromName ( node , flags ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; const name = node . value ; let type ; let isIncomplete = false ; const allowForwardReferences = ( flags & EvaluatorFlags . AllowForwardReferences ) !== 0 || fileInfo . isStubFile ; if ( ! evaluatorOptions . analyzeUnannotatedFunctions ) { const containingFunction = ParseTreeUtils . getEnclosingFunction ( node ) ; if ( containingFunction && ParseTreeUtils . isUnannotatedFunction ( containingFunction ) ) { return { node , type : AnyType . create ( ) , isIncomplete : false , } ; } } const symbolWithScope = lookUpSymbolRecursive ( node , name , ! allowForwardReferences , allowForwardReferences && ( flags & EvaluatorFlags . ExpectingTypeAnnotation ) !== 0 ) ; if ( symbolWithScope ) { let useCodeFlowAnalysis = ! allowForwardReferences ; if ( symbolWithScope . scope . type === ScopeType . Builtin ) { useCodeFlowAnalysis = false ; } const symbol = symbolWithScope . symbol ; const effectiveTypeInfo = getEffectiveTypeOfSymbolForUsage ( symbol , useCodeFlowAnalysis ? node : undefined ) ; const effectiveType = transformPossibleRecursiveTypeAlias ( effectiveTypeInfo . type ) ; if ( effectiveTypeInfo . isIncomplete ) { isIncomplete = true ; } if ( effectiveTypeInfo . isRecursiveDefinition && isNodeReachable ( node ) ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . recursiveDefinition ( ) . format ( { name } ) , node ) ; } const isSpecialBuiltIn = ! ! effectiveType && isInstantiableClass ( effectiveType ) && ClassType . isSpecialBuiltIn ( effectiveType ) ; type = effectiveType ; if ( useCodeFlowAnalysis && ! isSpecialBuiltIn ) { const typeAtStart = symbolWithScope . isBeyondExecutionScope || ! symbol . isInitiallyUnbound ( ) ? effectiveType : UnboundType . create ( ) ; const codeFlowTypeResult = getFlowTypeOfReference ( node , symbol . id , typeAtStart , false ) ; if ( codeFlowTypeResult . type ) { type = codeFlowTypeResult . type ; } if ( codeFlowTypeResult . isIncomplete ) { isIncomplete = true ; } if ( codeFlowTypeResult . usedOuterScopeAlias ) { const outerScopeSymbol = symbolWithScope . scope . parent ?. lookUpSymbolRecursive ( name ) ; if ( outerScopeSymbol ) { setSymbolAccessed ( fileInfo , outerScopeSymbol . symbol , node ) ; } } if ( ! codeFlowTypeResult . type && symbolWithScope . isBeyondExecutionScope ) { const outerScopeTypeResult = getCodeFlowTypeForCapturedVariable ( node , symbolWithScope , effectiveType ) ; if ( outerScopeTypeResult ?. type ) { type = outerScopeTypeResult . type ; } if ( outerScopeTypeResult ?. isIncomplete ) { isIncomplete = true ; } } } type = reportMissingTypeArguments ( node , type , flags ) ; setSymbolAccessed ( fileInfo , symbol , node ) ; if ( ( flags & EvaluatorFlags . ExpectingTypeAnnotation ) !== 0 ) { if ( effectiveTypeInfo . includesVariableDecl && ! type . typeAliasInfo ) { if ( ! isTypeAliasPlaceholder ( type ) && ! isTypeVar ( type ) && ! isUnknown ( type ) && ! fileInfo . isTypingStubFile ) { if ( ! TypeBase . isInstantiable ( type ) || ( flags & EvaluatorFlags . DoNotSpecialize ) !== 0 ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeAnnotationVariable ( ) , node ) ; type = UnknownType . create ( ) ; } } } } } else { if ( name !== 'reveal_type' && name !== 'reveal_locals' ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportUndefinedVariable , DiagnosticRule . reportUndefinedVariable , Localizer . Diagnostic . symbolIsUndefined ( ) . format ( { name } ) , node ) ; } type = UnknownType . create ( ) ; } if ( isParamSpec ( type ) ) { if ( flags & EvaluatorFlags . ParamSpecDisallowed ) { addError ( Localizer . Diagnostic . paramSpecContext ( ) , node ) ; type = UnknownType . create ( ) ; } } if ( isTypeVar ( type ) && ( flags & EvaluatorFlags . ExpectingType ) === 0 && type . details . name === name ) { const typeVarType = type . details . isVariadic ? getTypingType ( node , 'TypeVarTuple' ) : getTypingType ( node , 'TypeVar' ) ; if ( typeVarType && isInstantiableClass ( typeVarType ) ) { type = ClassType . cloneAsInstance ( typeVarType ) ; } else { type = UnknownType . create ( ) ; } } if ( ( flags & EvaluatorFlags . ExpectingType ) !== 0 ) { if ( ( flags & EvaluatorFlags . AllowGenericClassType ) === 0 ) { if ( isInstantiableClass ( type ) && ClassType . isBuiltIn ( type , 'Generic' ) ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . genericNotAllowed ( ) , node ) ; } } } if ( isTypeVar ( type ) && ! type . details . isSynthesized ) { type = validateTypeVarUsage ( node , type , flags ) ; } return { type , node , isIncomplete } ; } function getCodeFlowTypeForCapturedVariable ( node , symbolWithScope , effectiveType ) { if ( ! symbolWithScope . symbol . getDeclarations ( ) . every ( ( decl ) => decl . type === DeclarationType . Variable || decl . type === DeclarationType . Parameter ) ) { return undefined ; } const scopeHierarchy = ScopeUtils . getScopeHierarchy ( node , symbolWithScope . scope ) ; if ( scopeHierarchy && scopeHierarchy . length >= 2 && scopeHierarchy . every ( ( s ) => s . type === ScopeType . Function || s . type === ScopeType . Module ) ) { const innerScopeNode = ScopeUtils . findTopNodeInScope ( node , scopeHierarchy [ scopeHierarchy . length - 2 ] ) ; if ( innerScopeNode && ( innerScopeNode . nodeType === ParseNodeType . Function || innerScopeNode . nodeType === ParseNodeType . Lambda ) ) { const innerScopeCodeFlowNode = AnalyzerNodeInfo . getFlowNode ( innerScopeNode ) ; if ( innerScopeCodeFlowNode ) { if ( symbolWithScope . symbol . getDeclarations ( ) . every ( ( decl ) => { if ( decl . type === DeclarationType . Parameter ) { return true ; } const declCodeFlowNode = AnalyzerNodeInfo . getFlowNode ( decl . node ) ; if ( ! declCodeFlowNode ) { return false ; } if ( declCodeFlowNode === innerScopeCodeFlowNode ) { return true ; } return ! codeFlowEngine . isFlowNodeReachable ( declCodeFlowNode , innerScopeCodeFlowNode ) ; } ) ) { return getFlowTypeOfReference ( node , symbolWithScope . symbol . id , effectiveType , false , innerScopeNode ) ; } } } } return undefined ; } function validateTypeVarUsage ( node , type , flags ) { if ( TypeBase . isInstantiable ( type ) && ! isTypeAliasPlaceholder ( type ) ) { const scopedTypeVarInfo = findScopedTypeVar ( node , type ) ; type = scopedTypeVarInfo . type ; if ( ( flags & EvaluatorFlags . DisallowTypeVarsWithScopeId ) !== 0 && type . scopeId !== undefined ) { if ( ! type . details . isSynthesized && ! type . details . isParamSpec ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeVarUsedByOuterScope ( ) . format ( { name : type . details . name } ) , node ) ; } } else if ( ( flags & EvaluatorFlags . AssociateTypeVarsWithCurrentScope ) !== 0 ) { if ( type . scopeId === undefined ) { if ( ! scopedTypeVarInfo . foundInterveningClass ) { let enclosingScope = ParseTreeUtils . getEnclosingClassOrFunction ( node ) ; if ( enclosingScope && node . parent ?. nodeType === ParseNodeType . MemberAccess && node . parent . leftExpression === node ) { const memberName = node . parent . memberName . value ; if ( memberName === 'args' || memberName === 'kwargs' ) { const outerFunctionScope = ParseTreeUtils . getEnclosingClassOrFunction ( enclosingScope ) ; if ( outerFunctionScope ?. nodeType === ParseNodeType . Function ) { enclosingScope = outerFunctionScope ; } else if ( ! scopedTypeVarInfo . type . scopeId ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . paramSpecNotUsedByOuterScope ( ) . format ( { name : type . details . name , } ) , node ) ; } } } if ( enclosingScope ) { type = TypeVarType . cloneForScopeId ( type , getScopeIdForNode ( enclosingScope ) , enclosingScope . name . value , enclosingScope . nodeType === ParseNodeType . Function ? TypeVarScopeType . Function : TypeVarScopeType . Class ) ; } else { fail ( 'AssociateTypeVarsWithCurrentScope flag was set but enclosing scope not found' ) ; } } else { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeVarUsedByOuterScope ( ) . format ( { name : type . details . name } ) , node ) ; } } } else if ( ( flags & EvaluatorFlags . DisallowTypeVarsWithoutScopeId ) !== 0 ) { if ( ( type . scopeId === undefined || scopedTypeVarInfo . foundInterveningClass ) && ! type . details . isSynthesized ) { const message = isParamSpec ( type ) ? Localizer . Diagnostic . paramSpecNotUsedByOuterScope ( ) : Localizer . Diagnostic . typeVarNotUsedByOuterScope ( ) ; addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , message . format ( { name : type . details . name } ) , node ) ; } } } if ( type . isVariadicUnpacked ) { type = TypeVarType . cloneForPacked ( type ) ; } return type ; } function reportMissingTypeArguments ( node , type , flags ) { if ( ( flags & EvaluatorFlags . DoNotSpecialize ) === 0 ) { if ( isInstantiableClass ( type ) ) { if ( ( flags & EvaluatorFlags . ExpectingType ) !== 0 ) { if ( requiresTypeArguments ( type ) && ! type . typeArguments ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportMissingTypeArgument , DiagnosticRule . reportMissingTypeArgument , Localizer . Diagnostic . typeArgsMissingForClass ( ) . format ( { name : type . aliasName || type . details . name , } ) , node ) ; } } if ( ! type . typeArguments ) { type = createSpecializedClassType ( type , undefined , flags , node ) ; } } if ( ( flags & EvaluatorFlags . ExpectingType ) !== 0 && type . typeAliasInfo && type . typeAliasInfo . typeParameters && type . typeAliasInfo . typeParameters . length > 0 && ! type . typeAliasInfo . typeArguments ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportMissingTypeArgument , DiagnosticRule . reportMissingTypeArgument , Localizer . Diagnostic . typeArgsMissingForAlias ( ) . format ( { name : type . typeAliasInfo . name , } ) , node ) ; type = TypeBase . cloneForTypeAlias ( type , type . typeAliasInfo . name , type . typeAliasInfo . fullName , type . typeAliasInfo . typeVarScopeId , type . typeAliasInfo . typeParameters , type . typeAliasInfo . typeParameters . map ( ( param ) => UnknownType . create ( ) ) ) ; } } return type ; } function getScopeIdForNode ( node ) { let name = '' ; if ( node . nodeType === ParseNodeType . Class ) { name = node . name . value ; } else if ( node . nodeType === ParseNodeType . Function ) { name = node . name . value ; } const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; return `${ fileInfo . filePath }.${ node . start . toString ( ) }-${ name }` ; } function getTypeVarScopesForNode ( node ) { const scopeIds = [ ] ; let curNode = node ; while ( curNode ) { curNode = ParseTreeUtils . getTypeVarScopeNode ( curNode ) ; if ( ! curNode ) { break ; } scopeIds . push ( getScopeIdForNode ( curNode ) ) ; curNode = curNode . parent ; } return scopeIds ; } function findScopedTypeVar ( node , type ) { let curNode = node ; let nestedClassCount = 0 ; assert ( TypeBase . isInstantiable ( type ) ) ; while ( curNode ) { curNode = ParseTreeUtils . getTypeVarScopeNode ( curNode , node . parent ?. nodeType === ParseNodeType . MemberAccess ) ; if ( ! curNode ) { break ; } let typeVarsForScope ; if ( curNode . nodeType === ParseNodeType . Class ) { const classTypeInfo = getTypeOfClass ( curNode ) ; if ( classTypeInfo ) { typeVarsForScope = classTypeInfo . classType . details . typeParameters ; } nestedClassCount ++ ; } else if ( curNode . nodeType === ParseNodeType . Function ) { const functionTypeInfo = getTypeOfFunction ( curNode ) ; if ( functionTypeInfo ) { typeVarsForScope = [ ] ; functionTypeInfo . functionType . details . parameters . forEach ( ( param ) => { if ( param . hasDeclaredType ) { addTypeVarsToListIfUnique ( typeVarsForScope ! , getTypeVarArgumentsRecursive ( param . type ) ) ; } } ) ; if ( functionTypeInfo . functionType . details . declaredReturnType ) { addTypeVarsToListIfUnique ( typeVarsForScope ! , getTypeVarArgumentsRecursive ( functionTypeInfo . functionType . details . declaredReturnType ) ) ; } } } else if ( curNode . nodeType === ParseNodeType . Module ) { break ; } if ( typeVarsForScope ) { const match = typeVarsForScope . find ( ( typeVar ) => typeVar . details . name === type . details . name ) ; if ( match && match . scopeId ) { return { type : nestedClassCount > 1 ? type : ( convertToInstantiable ( match ) as TypeVarType ) , foundInterveningClass : nestedClassCount > 1 , } ; } } curNode = curNode . parent ; } curNode = node ; while ( curNode ) { if ( curNode . nodeType === ParseNodeType . Assignment ) { const leftType = readTypeCache ( curNode . leftExpression , EvaluatorFlags . None ) ; if ( leftType && isTypeVar ( leftType ) && leftType . details . recursiveTypeAliasScopeId && leftType . details . recursiveTypeAliasName ) { return { type : TypeVarType . cloneForScopeId ( type , leftType . details . recursiveTypeAliasScopeId , leftType . details . recursiveTypeAliasName , TypeVarScopeType . TypeAlias ) , foundInterveningClass : false , } ; } } curNode = curNode . parent ; } return { type , foundInterveningClass : false } ; } function getTypeFromMemberAccess ( node , flags ) { const baseTypeFlags = EvaluatorFlags . DoNotSpecialize | ( flags & ( EvaluatorFlags . ExpectingType | EvaluatorFlags . ExpectingTypeAnnotation | EvaluatorFlags . VariableTypeAnnotation | EvaluatorFlags . AllowForwardReferences | EvaluatorFlags . NotParsedByInterpreter | EvaluatorFlags . DisallowTypeVarsWithScopeId | EvaluatorFlags . DisallowTypeVarsWithoutScopeId | EvaluatorFlags . AssociateTypeVarsWithCurrentScope ) ) ; const baseTypeResult = getTypeOfExpression ( node . leftExpression , undefined , baseTypeFlags ) ; if ( isTypeAliasPlaceholder ( baseTypeResult . type ) ) { return { node , type : UnknownType . create ( ) , isIncomplete : true , } ; } const memberTypeResult = getTypeFromMemberAccessWithBaseType ( node , baseTypeResult , { method : 'get' } , flags ) ; if ( isCodeFlowSupportedForReference ( node ) ) { writeTypeCache ( node , memberTypeResult . type , flags , true ) ; writeTypeCache ( node . memberName , memberTypeResult . type , flags , true ) ; let initialType = memberTypeResult . type ; let isInitialTypeIncomplete = ! ! memberTypeResult . isIncomplete ; if ( isUnbound ( initialType ) ) { const baseType = makeTopLevelTypeVarsConcrete ( baseTypeResult . type ) ; let classMemberInfo ; if ( isInstantiableClass ( baseType ) ) { classMemberInfo = lookUpClassMember ( baseType , node . memberName . value , ClassMemberLookupFlags . SkipOriginalClass ) ; } else if ( isClassInstance ( baseType ) ) { classMemberInfo = lookUpObjectMember ( baseType , node . memberName . value , ClassMemberLookupFlags . SkipOriginalClass ) ; } if ( classMemberInfo ) { initialType = getTypeOfMember ( classMemberInfo ) ; isInitialTypeIncomplete = false ; } } const codeFlowTypeResult = getFlowTypeOfReference ( node , indeterminateSymbolId , initialType , isInitialTypeIncomplete ) ; if ( codeFlowTypeResult . type ) { memberTypeResult . type = codeFlowTypeResult . type ; } if ( codeFlowTypeResult . isIncomplete ) { memberTypeResult . isIncomplete = true ; } memberTypeResult . type = reportMissingTypeArguments ( node , memberTypeResult . type , flags ) ; deleteTypeCacheEntry ( node ) ; deleteTypeCacheEntry ( node . memberName ) ; } if ( baseTypeResult . isIncomplete ) { memberTypeResult . isIncomplete = true ; } return memberTypeResult ; } function getTypeFromMemberAccessWithBaseType ( node , baseTypeResult , usage , flags ) { let baseType = baseTypeResult . type ; const memberName = node . memberName . value ; let diag = new DiagnosticAddendum ( ) ; const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; let type ; let isIncomplete = ! ! baseTypeResult . isIncomplete ; let isAsymmetricDescriptor ; if ( baseTypeResult . isIncomplete && isUnbound ( baseTypeResult . type ) ) { return { type : UnknownType . create ( ) , node , isIncomplete : true } ; } if ( isUnion ( baseType ) && TypeBase . isSpecialForm ( baseType ) ) { if ( objectType ) { baseType = objectType ; } } const getTypeFromNoneBase = ( ) => { if ( noneType && isInstantiableClass ( noneType ) ) { const typeResult = getTypeFromObjectMember ( node . memberName , noneType , memberName , usage , diag , undefined , baseTypeResult . bindToType ) ; return typeResult ; } return undefined ; } ; if ( isParamSpec ( baseType ) && baseType . paramSpecAccess ) { baseType = makeTopLevelTypeVarsConcrete ( baseType ) ; } switch ( baseType . category ) { case TypeCategory . Any : case TypeCategory . Unknown : { type = baseType ; break ; } case TypeCategory . Never : { type = UnknownType . create ( ) ; break ; } case TypeCategory . TypeVar : { if ( baseType . details . isParamSpec ) { if ( memberName === 'args' ) { const paramNode = ParseTreeUtils . getEnclosingParameter ( node ) ; if ( ! paramNode || paramNode . category !== ParameterCategory . VarArgList ) { addError ( Localizer . Diagnostic . paramSpecArgsUsage ( ) , node ) ; return { type : UnknownType . create ( ) , node , isIncomplete } ; } return { type : TypeVarType . cloneForParamSpecAccess ( baseType , 'args' ) , node , isIncomplete } ; } if ( memberName === 'kwargs' ) { const paramNode = ParseTreeUtils . getEnclosingParameter ( node ) ; if ( ! paramNode || paramNode . category !== ParameterCategory . VarArgDictionary ) { addError ( Localizer . Diagnostic . paramSpecKwargsUsage ( ) , node ) ; return { type : UnknownType . create ( ) , node , isIncomplete } ; } return { type : TypeVarType . cloneForParamSpecAccess ( baseType , 'kwargs' ) , node , isIncomplete } ; } if ( ! isIncomplete ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . paramSpecUnknownMember ( ) . format ( { name : memberName } ) , node ) ; } return { type : UnknownType . create ( ) , node , isIncomplete } ; } if ( flags & EvaluatorFlags . ExpectingType ) { if ( ! isIncomplete ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeVarNoMember ( ) . format ( { type : printType ( baseType ) , name : memberName , } ) , node . leftExpression ) ; } return { type : UnknownType . create ( ) , node , isIncomplete } ; } if ( baseType . details . recursiveTypeAliasName ) { return { type : UnknownType . create ( ) , node , isIncomplete : true } ; } return getTypeFromMemberAccessWithBaseType ( node , { type : makeTopLevelTypeVarsConcrete ( baseType ) , node , bindToType : baseType , isIncomplete , } , usage , EvaluatorFlags . None ) ; } case TypeCategory . Class : { if ( TypeBase . isInstantiable ( baseType ) ) { const typeResult = getTypeFromClassMember ( node . memberName , baseType , memberName , usage , diag , MemberAccessFlags . None , baseTypeResult . bindToType ) ; type = typeResult ?. type ; if ( typeResult ?. isIncomplete ) { isIncomplete = true ; } if ( typeResult ?. isAsymmetricDescriptor ) { isAsymmetricDescriptor = true ; } } else if ( ClassType . isBuiltIn ( baseType , 'type' ) && objectType && isClassInstance ( objectType ) ) { const typeResult = getTypeFromClassMember ( node . memberName , ClassType . cloneAsInstantiable ( objectType ) , memberName , usage , diag , MemberAccessFlags . None , baseTypeResult . bindToType ? ( convertToInstance ( baseTypeResult . bindToType ) as ClassType | TypeVarType ) : undefined ) ; type = typeResult ?. type ; if ( typeResult ?. isIncomplete ) { isIncomplete = true ; } if ( typeResult ?. isAsymmetricDescriptor ) { isAsymmetricDescriptor = true ; } } else { if ( ClassType . isEnumClass ( baseType ) ) { const literalValue = baseType . literalValue ; if ( literalValue instanceof EnumLiteral ) { if ( memberName === 'name' || memberName === '_name_' ) { const strClass = getBuiltInType ( node , 'str' ) ; if ( isInstantiableClass ( strClass ) ) { return { node , type : ClassType . cloneAsInstance ( ClassType . cloneWithLiteral ( strClass , literalValue . itemName ) ) , isIncomplete , } ; } } else if ( memberName === 'value' || memberName === '_value_' ) { return { node , type : literalValue . itemType , isIncomplete } ; } } } const typeResult = getTypeFromObjectMember ( node . memberName , baseType , memberName , usage , diag , undefined , baseTypeResult . bindToType ) ; if ( typeResult ) { type = addConditionToType ( typeResult . type , getTypeCondition ( baseType ) ) ; } if ( typeResult ?. isIncomplete ) { isIncomplete = true ; } if ( typeResult ?. isAsymmetricDescriptor ) { isAsymmetricDescriptor = true ; } } break ; } case TypeCategory . Module : { const symbol = ModuleType . getField ( baseType , memberName ) ; if ( symbol && ! symbol . isExternallyHidden ( ) ) { if ( usage . method === 'get' ) { setSymbolAccessed ( AnalyzerNodeInfo . getFileInfo ( node ) , symbol , node . memberName ) ; } type = getEffectiveTypeOfSymbolForUsage ( symbol , undefined , true ) . type ; if ( isTypeVar ( type ) ) { type = validateTypeVarUsage ( node , type , flags ) ; } if ( isUnbound ( type ) ) { type = UnknownType . create ( ) ; } if ( symbol . isPrivateMember ( ) ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportPrivateUsage , DiagnosticRule . reportPrivateUsage , Localizer . Diagnostic . privateUsedOutsideOfModule ( ) . format ( { name : memberName , } ) , node . memberName ) ; } if ( symbol . isPrivatePyTypedImport ( ) ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportPrivateImportUsage , DiagnosticRule . reportPrivateImportUsage , Localizer . Diagnostic . privateImportFromPyTypedModule ( ) . format ( { name : memberName , module : baseType . moduleName , } ) , node . memberName ) ; } } else { if ( usage . method === 'get' ) { const getAttrSymbol = ModuleType . getField ( baseType , '__getattr__' ) ; if ( getAttrSymbol ) { const isModuleGetAttrSupported = fileInfo . executionEnvironment . pythonVersion >= PythonVersion . V3_7 || getAttrSymbol . getDeclarations ( ) . some ( ( decl ) => decl . path . toLowerCase ( ) . endsWith ( '.pyi' ) ) ; if ( isModuleGetAttrSupported ) { const getAttrTypeResult = getEffectiveTypeOfSymbolForUsage ( getAttrSymbol ) ; if ( isFunction ( getAttrTypeResult . type ) ) { type = getFunctionEffectiveReturnType ( getAttrTypeResult . type ) ; if ( getAttrTypeResult . isIncomplete ) { isIncomplete = true ; } } } } } if ( ! type ) { if ( ! isIncomplete ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . moduleUnknownMember ( ) . format ( { name : memberName } ) , node . memberName ) ; } type = evaluatorOptions . evaluateUnknownImportsAsAny ? AnyType . create ( ) : UnknownType . create ( ) ; } } break ; } case TypeCategory . Union : { type = mapSubtypes ( baseType , ( subtype ) => { if ( isNoneInstance ( subtype ) ) { const typeResult = getTypeFromNoneBase ( ) ; if ( typeResult ) { type = addConditionToType ( typeResult . type , getTypeCondition ( baseType ) ) ; if ( typeResult . isIncomplete ) { isIncomplete = true ; } return type ; } else { if ( ! isIncomplete ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportOptionalMemberAccess , DiagnosticRule . reportOptionalMemberAccess , Localizer . Diagnostic . noneUnknownMember ( ) . format ( { name : memberName } ) , node . memberName ) ; } return undefined ; } } else if ( isUnbound ( subtype ) ) { return undefined ; } else { const typeResult = getTypeFromMemberAccessWithBaseType ( node , { type : subtype , node , isIncomplete : baseTypeResult . isIncomplete , } , usage , EvaluatorFlags . None ) ; if ( typeResult . isIncomplete ) { isIncomplete = true ; } return typeResult . type ; } } ) ; break ; } case TypeCategory . Function : case TypeCategory . OverloadedFunction : { if ( memberName === '__defaults__' ) { type = AnyType . create ( ) ; } else if ( memberName === '__self__' ) { const functionType = isFunction ( baseType ) ? baseType : baseType . overloads [ 0 ] ; if ( functionType . preBoundFlags !== undefined && ( functionType . preBoundFlags & FunctionTypeFlags . StaticMethod ) === 0 ) { type = functionType . boundToType ; } } else { if ( ! functionObj ) { type = AnyType . create ( ) ; } else { type = getTypeFromMemberAccessWithBaseType ( node , { type : functionObj , node } , usage , flags ) . type ; } } break ; } case TypeCategory . None : { const typeResult = getTypeFromNoneBase ( ) ; if ( typeResult ) { type = addConditionToType ( typeResult . type , getTypeCondition ( baseType ) ) ; if ( typeResult . isIncomplete ) { isIncomplete = true ; } } break ; } default : diag . addMessage ( Localizer . DiagnosticAddendum . typeUnsupported ( ) . format ( { type : printType ( baseType ) } ) ) ; break ; } if ( ! type ) { const isFunctionRule = isFunction ( baseType ) || isOverloadedFunction ( baseType ) || ( isClassInstance ( baseType ) && ClassType . isBuiltIn ( baseType , 'function' ) ) ; if ( ! baseTypeResult . isIncomplete ) { let diagMessage = Localizer . Diagnostic . memberAccess ( ) ; if ( usage . method === 'set' ) { diagMessage = Localizer . Diagnostic . memberSet ( ) ; } else if ( usage . method === 'del' ) { diagMessage = Localizer . Diagnostic . memberDelete ( ) ; } if ( usage . setExpectedTypeDiag ) { diag = usage . setExpectedTypeDiag ; } const [ ruleSet , rule ] = isFunctionRule ? [ fileInfo . diagnosticRuleSet . reportFunctionMemberAccess , DiagnosticRule . reportFunctionMemberAccess ] : [ fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues ] ; addDiagnostic ( ruleSet , rule , diagMessage . format ( { name : memberName , type : printType ( baseType ) } ) + diag . getString ( ) , node . memberName ) ; } type = isFunctionRule ? AnyType . create ( ) : UnknownType . create ( ) ; } if ( ( flags & EvaluatorFlags . DoNotSpecialize ) === 0 ) { if ( isInstantiableClass ( type ) && ! type . typeArguments ) { type = createSpecializedClassType ( type , undefined , flags , node ) ; } } if ( usage . method === 'get' ) { let skipPartialUnknownCheck = isIncomplete ; if ( isInstantiableClass ( type ) && ParseTreeUtils . isNodeContainedWithinNodeType ( node , ParseNodeType . Argument ) ) { skipPartialUnknownCheck = true ; } if ( ! skipPartialUnknownCheck ) { reportPossibleUnknownAssignment ( fileInfo . diagnosticRuleSet . reportUnknownMemberType , DiagnosticRule . reportUnknownMemberType , node . memberName , type , node , false ) ; } } return { type , node , isIncomplete , isAsymmetricDescriptor } ; } function getTypeFromClassMemberName ( errorNode , classType , memberName , usage , diag , flags , bindToType ? ) { let classLookupFlags = ClassMemberLookupFlags . Default ; if ( flags & MemberAccessFlags . AccessClassMembersOnly ) { classLookupFlags |= ClassMemberLookupFlags . SkipInstanceVariables ; } if ( flags & MemberAccessFlags . SkipBaseClasses ) { classLookupFlags |= ClassMemberLookupFlags . SkipBaseClasses ; } if ( flags & MemberAccessFlags . SkipObjectBaseClass ) { classLookupFlags |= ClassMemberLookupFlags . SkipObjectBaseClass ; } if ( flags & MemberAccessFlags . SkipTypeBaseClass ) { classLookupFlags |= ClassMemberLookupFlags . SkipTypeBaseClass ; } if ( flags & MemberAccessFlags . SkipOriginalClass ) { classLookupFlags |= ClassMemberLookupFlags . SkipOriginalClass ; } let memberInfo = lookUpClassMember ( classType , memberName , classLookupFlags | ClassMemberLookupFlags . DeclaredTypesOnly ) ; if ( ! memberInfo ) { memberInfo = lookUpClassMember ( classType , memberName , classLookupFlags ) ; } if ( memberInfo ) { let type ; let isTypeIncomplete = false ; if ( memberInfo . symbol . isInitVar ( ) ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . memberIsInitVar ( ) . format ( { name : memberName } ) ) ; } return undefined ; } if ( usage . method !== 'get' ) { const containingClass = ParseTreeUtils . getEnclosingClass ( errorNode ) ; if ( containingClass ) { const containingClassType = getTypeOfClass ( containingClass ) ?. classType ; if ( containingClassType && isInstantiableClass ( containingClassType ) && ClassType . isSameGenericClass ( containingClassType , classType ) ) { type = getDeclaredTypeOfSymbol ( memberInfo . symbol ) || UnknownType . create ( ) ; if ( type && isInstantiableClass ( memberInfo . classType ) ) { type = partiallySpecializeType ( type , memberInfo . classType ) ; } } } } if ( ! type ) { const selfClass = bindToType ? undefined : classType ; const typeResult = getTypeOfMemberInternal ( errorNode , memberInfo , selfClass ) ; if ( typeResult ) { type = typeResult . type ; if ( typeResult . isIncomplete ) { isTypeIncomplete = true ; } } else { type = UnknownType . create ( ) ; } } if ( ClassType . isTypedDictClass ( classType ) ) { const typedDecls = memberInfo . symbol . getTypedDeclarations ( ) ; if ( typedDecls . length > 0 && typedDecls [ 0 ] . type === DeclarationType . Variable ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . memberUnknown ( ) . format ( { name : memberName } ) ) ; } return undefined ; } } if ( usage . method === 'get' ) { if ( isInstantiableClass ( memberInfo . classType ) && ClassType . isSameGenericClass ( memberInfo . classType , classType ) ) { setSymbolAccessed ( AnalyzerNodeInfo . getFileInfo ( errorNode ) , memberInfo . symbol , errorNode ) ; } } const descriptorResult = applyDescriptorAccessMethod ( type , memberInfo , classType , bindToType , ( flags & MemberAccessFlags . AccessClassMembersOnly ) === 0 , flags , errorNode , memberName , usage , diag ) ; if ( ! descriptorResult ) { return undefined ; } type = descriptorResult . type ; if ( usage . method === 'set' && usage . setType ) { if ( ! canAssignType ( type , usage . setType , diag ?. createAddendum ( ) ) ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . memberAssignment ( ) . format ( { type : printType ( usage . setType ) , name : memberName , classType : printObjectTypeForClass ( classType ) , } ) ) ; } return undefined ; } if ( isInstantiableClass ( memberInfo . classType ) && ClassType . isFrozenDataClass ( memberInfo . classType ) && ( flags & MemberAccessFlags . AccessClassMembersOnly ) === 0 ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . dataClassFrozen ( ) . format ( { name : printType ( ClassType . cloneAsInstance ( memberInfo . classType ) ) , } ) ) ; } return undefined ; } } return { type , isTypeIncomplete , isClassMember : ! memberInfo . isInstanceMember , isClassVar : memberInfo . isClassVar , classType : memberInfo . classType , isAsymmetricDescriptor : descriptorResult . isAsymmetricDescriptor , } ; } if ( ( flags & ( MemberAccessFlags . AccessClassMembersOnly | MemberAccessFlags . SkipAttributeAccessOverride ) ) === 0 ) { const generalAttrType = applyAttributeAccessOverride ( classType , errorNode , usage , memberName ) ; if ( generalAttrType ) { const descriptorResult = applyDescriptorAccessMethod ( generalAttrType , memberInfo , classType , bindToType , ! ! bindToType , flags , errorNode , memberName , usage , diag ) ; if ( ! descriptorResult ) { return undefined ; } return { type : descriptorResult . type , isTypeIncomplete : false , isClassMember : false , isClassVar : false , isAsymmetricDescriptor : descriptorResult . isAsymmetricDescriptor , } ; } } if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . memberUnknown ( ) . format ( { name : memberName } ) ) ; } return undefined ; } function applyDescriptorAccessMethod ( type , memberInfo , baseTypeClass , bindToType , isAccessedThroughObject , flags , errorNode , memberName , usage , diag ) { const treatConstructorAsClassMember = ( flags & MemberAccessFlags . TreatConstructorAsClassMethod ) !== 0 ; let isTypeValid = true ; let isAsymmetricDescriptor = false ; type = mapSubtypes ( type , ( subtype ) => { if ( isClass ( subtype ) ) { let lookupClass = subtype ; let isAccessedThroughMetaclass = false ; if ( TypeBase . isInstantiable ( subtype ) ) { if ( subtype . details . effectiveMetaclass && isInstantiableClass ( subtype . details . effectiveMetaclass ) ) { if ( isAccessedThroughObject || usage . method === 'get' ) { lookupClass = convertToInstance ( subtype . details . effectiveMetaclass ) as ClassType ; isAccessedThroughMetaclass = true ; } else { lookupClass = undefined ; } } else { lookupClass = undefined ; } } if ( lookupClass ) { let accessMethodName ; if ( usage . method === 'get' ) { accessMethodName = '__get__' ; } else if ( usage . method === 'set' ) { accessMethodName = '__set__' ; } else { accessMethodName = '__delete__' ; } const accessMethod = lookUpClassMember ( lookupClass , accessMethodName , ClassMemberLookupFlags . SkipInstanceVariables ) ; if ( ClassType . isPropertyClass ( lookupClass ) ) { if ( usage . method === 'set' ) { if ( ! accessMethod ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . propertyMissingSetter ( ) . format ( { name : memberName , } ) ) ; } isTypeValid = false ; return undefined ; } } else if ( usage . method === 'del' ) { if ( ! accessMethod ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . propertyMissingDeleter ( ) . format ( { name : memberName , } ) ) ; } isTypeValid = false ; return undefined ; } } } if ( accessMethod ) { let accessMethodType = getTypeOfMember ( accessMethod ) ; const argList = [ { argumentCategory : ArgumentCategory . Simple , type : ClassType . isClassProperty ( lookupClass ) ? baseTypeClass : isAccessedThroughObject ? bindToType || ClassType . cloneAsInstance ( baseTypeClass ) : NoneType . createInstance ( ) , } , ] ; if ( usage . method === 'get' ) { argList . push ( { argumentCategory : ArgumentCategory . Simple , type : baseTypeClass , } ) ; } else if ( usage . method === 'set' ) { argList . push ( { argumentCategory : ArgumentCategory . Simple , type : usage . setType || UnknownType . create ( ) , } ) ; } if ( ClassType . isPropertyClass ( lookupClass ) && memberInfo && isInstantiableClass ( memberInfo ! . classType ) ) { inferReturnTypeIfNecessary ( accessMethodType ) ; accessMethodType = partiallySpecializeType ( accessMethodType , memberInfo . classType ) ; if ( ( flags & MemberAccessFlags . AccessClassMembersOnly ) !== 0 && ClassType . isProtocolClass ( baseTypeClass ) ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . propertyAccessFromProtocolClass ( ) ) ; } isTypeValid = false ; } } if ( accessMethodType && ( isFunction ( accessMethodType ) || isOverloadedFunction ( accessMethodType ) ) ) { const methodType = accessMethodType ; const returnType = suppressDiagnostics ( errorNode , ( ) => { let bindToClass ; if ( ClassType . isPropertyClass ( subtype ) && ! isAccessedThroughMetaclass ) { if ( memberInfo && isInstantiableClass ( memberInfo . classType ) ) { bindToClass = memberInfo . classType ; } } else { if ( isInstantiableClass ( accessMethod . classType ) ) { bindToClass = accessMethod . classType ; } } const boundMethodType = bindFunctionToClassOrObject ( lookupClass , methodType , bindToClass , errorNode , undefined , undefined , isAccessedThroughMetaclass ? subtype : undefined ) ; if ( boundMethodType && ( isFunction ( boundMethodType ) || isOverloadedFunction ( boundMethodType ) ) ) { const typeVarMap = new TypeVarMap ( getTypeVarScopeId ( boundMethodType ) ) ; if ( bindToClass ) { typeVarMap . addSolveForScope ( getTypeVarScopeId ( bindToClass ) ) ; } const callResult = validateCallArguments ( errorNode , argList , boundMethodType , typeVarMap , true ) ; if ( callResult . argumentErrors ) { isTypeValid = false ; return AnyType . create ( ) ; } return usage . method === 'get' ? callResult . returnType || UnknownType . create ( ) : AnyType . create ( ) ; } return undefined ; } ) ; if ( usage . method === 'set' && isClass ( accessMethod . classType ) ) { if ( isAsymmetricDescriptorClass ( accessMethod . classType ) ) { isAsymmetricDescriptor = true ; } } if ( returnType ) { return returnType ; } } } } } else if ( isFunction ( subtype ) || isOverloadedFunction ( subtype ) ) { if ( ! isAccessedThroughObject || ( memberInfo && ! memberInfo . isInstanceMember ) ) { return bindFunctionToClassOrObject ( isAccessedThroughObject ? ClassType . cloneAsInstance ( baseTypeClass ) : baseTypeClass , subtype , memberInfo && isInstantiableClass ( memberInfo . classType ) ? memberInfo . classType : undefined , errorNode , undefined , treatConstructorAsClassMember , bindToType ) ; } } if ( usage . method === 'set' ) { if ( memberInfo ?. symbol . isClassVar ( ) ) { if ( flags & MemberAccessFlags . DisallowClassVarWrites ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . memberSetClassVar ( ) . format ( { name : memberName } ) ) ; } isTypeValid = false ; return undefined ; } } const finalTypeDecl = memberInfo ?. symbol . getDeclarations ( ) . find ( ( decl ) => isFinalVariableDeclaration ( decl ) ) ; if ( finalTypeDecl && ! ParseTreeUtils . isNodeContainedWithin ( errorNode , finalTypeDecl . node ) ) { const enclosingFunctionNode = ParseTreeUtils . getEnclosingFunction ( errorNode ) ; if ( ! enclosingFunctionNode || enclosingFunctionNode . name . value !== '__init__' ) { if ( diag ) { diag . addMessage ( Localizer . Diagnostic . finalReassigned ( ) . format ( { name : memberName } ) ) ; } isTypeValid = false ; return undefined ; } } if ( memberInfo ?. isInstanceMember && isClass ( memberInfo . classType ) && ClassType . isReadOnlyInstanceVariables ( memberInfo . classType ) ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . readOnlyAttribute ( ) . format ( { name : memberName } ) ) ; } isTypeValid = false ; return undefined ; } let enforceTargetType = false ; if ( memberInfo && memberInfo . symbol . hasTypedDeclarations ( ) ) { enforceTargetType = true ; } else { if ( memberInfo && ! memberInfo . symbol . getDeclarations ( ) . some ( ( decl ) => decl . node === errorNode ) ) { enforceTargetType = true ; } } if ( enforceTargetType ) { let effectiveType = subtype ; if ( isAccessedThroughObject ) { if ( ! memberInfo ! . isInstanceMember && isFunction ( subtype ) ) { if ( FunctionType . isClassMethod ( subtype ) || FunctionType . isInstanceMethod ( subtype ) ) { effectiveType = FunctionType . clone ( subtype , true ) ; } } } return effectiveType ; } } return subtype ; } ) ; if ( ! isTypeValid ) { return undefined ; } return { type , isAsymmetricDescriptor } ; } function isAsymmetricDescriptorClass ( classType ) { if ( classType . isAsymmetricDescriptor !== undefined ) { return classType . isAsymmetricDescriptor ; } let isAsymmetric = false ; const getterSymbolResult = lookUpClassMember ( classType , '__get__' , ClassMemberLookupFlags . SkipBaseClasses ) ; const setterSymbolResult = lookUpClassMember ( classType , '__set__' , ClassMemberLookupFlags . SkipBaseClasses ) ; if ( ! getterSymbolResult || ! setterSymbolResult ) { isAsymmetric = false ; } else { const getterType = getEffectiveTypeOfSymbol ( getterSymbolResult . symbol ) ; const setterType = getEffectiveTypeOfSymbol ( setterSymbolResult . symbol ) ; if ( isFunction ( getterType ) && isFunction ( setterType ) ) { if ( setterType . details . parameters . length >= 3 && getterType . details . declaredReturnType ) { const setterValueType = FunctionType . getEffectiveParameterType ( setterType , 2 ) ; const getterReturnType = FunctionType . getSpecializedReturnType ( getterType ) ?? UnknownType . create ( ) ; if ( ! isTypeSame ( setterValueType , getterReturnType ) ) { isAsymmetric = true ; } } } } classType . isAsymmetricDescriptor = isAsymmetric ; return isAsymmetric ; } function applyAttributeAccessOverride ( classType , errorNode , usage , memberName ) { if ( usage . method === 'get' ) { let getAttrType = getTypeFromClassMember ( errorNode , classType , '__getattribute__' , { method : 'get' } , undefined , MemberAccessFlags . SkipObjectBaseClass ) ?. type ; if ( ! getAttrType ) { getAttrType = getTypeFromClassMember ( errorNode , classType , '__getattr__' , { method : 'get' } , undefined , MemberAccessFlags . SkipObjectBaseClass ) ?. type ; } if ( getAttrType && isOverloadedFunction ( getAttrType ) ) { let nameLiteralType = AnyType . create ( ) ; if ( strClassType && isInstantiableClass ( strClassType ) ) { nameLiteralType = ClassType . cloneWithLiteral ( ClassType . cloneAsInstance ( strClassType ) , memberName ) ; } getAttrType = getBestOverloadForArguments ( errorNode , getAttrType , [ { argumentCategory : ArgumentCategory . Simple , type : AnyType . create ( ) , } , { argumentCategory : ArgumentCategory . Simple , type : nameLiteralType , } , ] ) ; } if ( getAttrType && isFunction ( getAttrType ) ) { return getFunctionEffectiveReturnType ( getAttrType ) ; } } else if ( usage . method === 'set' ) { const setAttrType = getTypeFromClassMember ( errorNode , classType , '__setattr__' , { method : 'get' } , undefined , MemberAccessFlags . SkipObjectBaseClass ) ?. type ; if ( setAttrType ) { return AnyType . create ( ) ; } } else { assert ( usage . method === 'del' ) ; const delAttrType = getTypeFromClassMember ( errorNode , classType , '__detattr__' , { method : 'get' } , undefined , MemberAccessFlags . SkipObjectBaseClass ) ?. type ; if ( delAttrType ) { return AnyType . create ( ) ; } } return undefined ; } function getTypeFromIndex ( node , flags = EvaluatorFlags . None ) { const baseTypeResult = getTypeOfExpression ( node . baseExpression , undefined , flags | EvaluatorFlags . DoNotSpecialize ) ; if ( flags & EvaluatorFlags . ExpectingType ) { if ( node . baseExpression . nodeType === ParseNodeType . StringList ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; if ( ! fileInfo . isStubFile && fileInfo . executionEnvironment . pythonVersion < PythonVersion . V3_10 ) { addError ( Localizer . Diagnostic . stringNotSubscriptable ( ) , node . baseExpression ) ; } } } if ( ( flags & EvaluatorFlags . AllowForwardReferences ) === 0 ) { let skipSubscriptCheck = ( flags & EvaluatorFlags . VariableTypeAnnotation ) !== 0 ; if ( skipSubscriptCheck ) { const scopeNode = ParseTreeUtils . getExecutionScopeNode ( node ) ; if ( scopeNode ?. nodeType === ParseNodeType . Module ) { skipSubscriptCheck = false ; } } if ( ! skipSubscriptCheck ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; if ( isInstantiableClass ( baseTypeResult . type ) && ClassType . isBuiltIn ( baseTypeResult . type ) && ! baseTypeResult . type . aliasName ) { const minPythonVersion = nonSubscriptableBuiltinTypes . get ( baseTypeResult . type . details . fullName ) ; if ( minPythonVersion !== undefined && fileInfo . executionEnvironment . pythonVersion < minPythonVersion && ! fileInfo . isStubFile ) { addError ( Localizer . Diagnostic . classNotRuntimeSubscriptable ( ) . format ( { name : baseTypeResult . type . aliasName || baseTypeResult . type . details . name , } ) , node . baseExpression ) ; } } } } const indexTypeResult = getTypeFromIndexWithBaseType ( node , baseTypeResult . type , { method : 'get' } , flags ) ; if ( isCodeFlowSupportedForReference ( node ) ) { let baseTypeSupportsIndexNarrowing = true ; mapSubtypesExpandTypeVars ( baseTypeResult . type , undefined , ( subtype ) => { if ( ! isClassInstance ( subtype ) || ! ( ClassType . isBuiltIn ( subtype ) || ClassType . isTypedDictClass ( subtype ) ) ) { baseTypeSupportsIndexNarrowing = false ; } return undefined ; } ) ; if ( baseTypeSupportsIndexNarrowing ) { writeTypeCache ( node , indexTypeResult . type , flags , false ) ; const codeFlowTypeResult = getFlowTypeOfReference ( node , indeterminateSymbolId , indexTypeResult . type , ! ! baseTypeResult . isIncomplete || ! ! indexTypeResult . isIncomplete ) ; if ( codeFlowTypeResult . type ) { indexTypeResult . type = codeFlowTypeResult . type ; } if ( codeFlowTypeResult . isIncomplete ) { indexTypeResult . isIncomplete = true ; } deleteTypeCacheEntry ( node ) ; } } if ( baseTypeResult . isIncomplete ) { indexTypeResult . isIncomplete = true ; } if ( ( flags & EvaluatorFlags . RequiredAllowed ) !== 0 ) { if ( isInstantiableClass ( baseTypeResult . type ) ) { if ( ClassType . isBuiltIn ( baseTypeResult . type , 'Required' ) ) { indexTypeResult . isRequired = true ; } else if ( ClassType . isBuiltIn ( baseTypeResult . type , 'NotRequired' ) ) { indexTypeResult . isNotRequired = true ; } } } return indexTypeResult ; } function adjustTypeArgumentsForVariadicTypeVar ( typeArgs , typeParameters ) { const variadicIndex = typeParameters . findIndex ( ( param ) => isVariadicTypeVar ( param ) ) ; if ( variadicIndex >= 0 && variadicIndex < typeArgs . length ) { if ( tupleClassType && isInstantiableClass ( tupleClassType ) ) { const variadicTypeResults = typeArgs . slice ( variadicIndex , variadicIndex + 1 + typeArgs . length - typeParameters . length ) ; if ( variadicTypeResults . length === 1 && isVariadicTypeVar ( variadicTypeResults [ 0 ] . type ) ) { validateVariadicTypeVarIsUnpacked ( variadicTypeResults [ 0 ] . type , variadicTypeResults [ 0 ] . node ) ; } else { variadicTypeResults . forEach ( ( arg , index ) => { validateTypeArg ( arg , index === 0 , true ) ; } ) ; const variadicTypes = variadicTypeResults . length === 1 && variadicTypeResults [ 0 ] . isEmptyTupleShorthand ? [ ] : variadicTypeResults . map ( ( typeResult ) => convertToInstance ( typeResult . type ) ) ; const tupleObject = convertToInstance ( specializeTupleClass ( tupleClassType , variadicTypes , true , true , true ) ) ; typeArgs = [ ... typeArgs . slice ( 0 , variadicIndex ) , { node : typeArgs [ variadicIndex ] . node , type : tupleObject } , ... typeArgs . slice ( variadicIndex + 1 + typeArgs . length - typeParameters . length , typeArgs . length ) , ] ; } } } return typeArgs ; } function validateVariadicTypeVarIsUnpacked ( type , node ) { if ( ! type . isVariadicUnpacked ) { addError ( Localizer . Diagnostic . unpackedTypeVarTupleExpected ( ) . format ( { name1 : type . details . name , name2 : type . details . name , } ) , node ) ; return false ; } return true ; } function createSpecializedTypeAlias ( node , baseType , flags ) { if ( ! baseType . typeAliasInfo ?. typeParameters || ( baseType . typeAliasInfo . typeParameters . length === 0 && baseType . typeAliasInfo . typeArguments ) ) { return undefined ; } if ( ! TypeBase . isInstantiable ( baseType ) ) { return undefined ; } if ( baseType . typeAliasInfo . typeArguments ) { return undefined ; } const typeParameters = baseType . typeAliasInfo . typeParameters ; let typeArgs = adjustTypeArgumentsForVariadicTypeVar ( getTypeArgs ( node , flags ) , typeParameters ) ; if ( typeParameters . length === 1 && typeParameters [ 0 ] . details . isParamSpec && typeArgs ) { if ( typeArgs . every ( ( typeArg ) => ! isEllipsisType ( typeArg . type ) && ! typeArg . typeList && ! isParamSpec ( typeArg . type ) ) ) { typeArgs = [ { type : UnknownType . create ( ) , node : typeArgs [ 0 ] . node , typeList : typeArgs , } , ] ; } } if ( typeArgs . length > typeParameters . length && ! typeParameters . some ( ( typeVar ) => typeVar . details . isVariadic ) ) { addError ( Localizer . Diagnostic . typeArgsTooMany ( ) . format ( { name : printType ( baseType ) , expected : typeParameters . length , received : typeArgs . length , } ) , typeArgs [ typeParameters . length ] . node ) ; } const typeVarMap = new TypeVarMap ( baseType . typeAliasInfo . typeVarScopeId ) ; const diag = new DiagnosticAddendum ( ) ; typeParameters . forEach ( ( param , index ) => { if ( param . details . isParamSpec && index < typeArgs . length ) { if ( typeArgs [ index ] . typeList ) { const functionType = FunctionType . createInstantiable ( '' , '' , '' , FunctionTypeFlags . ParamSpecValue ) ; TypeBase . setSpecialForm ( functionType ) ; typeArgs [ index ] . typeList ! . forEach ( ( paramType , paramIndex ) => { FunctionType . addParameter ( functionType , { category : ParameterCategory . Simple , name : `__p${ paramIndex }` , isNameSynthesized : true , type : convertToInstance ( paramType . type ) , hasDeclaredType : true , } ) ; } ) ; canAssignTypeToTypeVar ( param , functionType , diag , typeVarMap ) ; } else if ( isParamSpec ( typeArgs [ index ] . type ) ) { canAssignTypeToTypeVar ( param , convertToInstance ( typeArgs [ index ] . type ) , diag , typeVarMap ) ; } else if ( isEllipsisType ( typeArgs [ index ] . type ) ) { const functionType = FunctionType . createInstantiable ( '' , '' , '' , FunctionTypeFlags . ParamSpecValue | FunctionTypeFlags . SkipArgsKwargsCompatibilityCheck ) ; TypeBase . setSpecialForm ( functionType ) ; FunctionType . addDefaultParameters ( functionType ) ; canAssignTypeToTypeVar ( param , functionType , diag , typeVarMap ) ; } else { addError ( Localizer . Diagnostic . typeArgListExpected ( ) , typeArgs [ index ] . node ) ; } } else { if ( index < typeArgs . length && typeArgs [ index ] . typeList ) { addError ( Localizer . Diagnostic . typeArgListNotAllowed ( ) , typeArgs [ index ] . node ) ; } const typeArgType = index < typeArgs . length ? convertToInstance ( typeArgs [ index ] . type ) : UnknownType . create ( ) ; canAssignTypeToTypeVar ( param , typeArgType , diag , typeVarMap ) ; } } ) ; if ( ! diag . isEmpty ( ) ) { addError ( Localizer . Diagnostic . typeNotSpecializable ( ) . format ( { type : printType ( baseType ) } ) + diag . getString ( ) , node ) ; } const aliasTypeArgs = [ ] ; baseType . typeAliasInfo . typeParameters ?. forEach ( ( typeParam ) => { let typeVarType ; if ( isParamSpec ( typeParam ) ) { const paramSpecValue = typeVarMap . getParamSpec ( typeParam ) ; typeVarType = paramSpecValue ? convertParamSpecValueToType ( paramSpecValue ) : UnknownType . create ( ) ; } else { typeVarType = typeVarMap . getTypeVarType ( typeParam ) ; } aliasTypeArgs . push ( typeVarType || UnknownType . create ( ) ) ; } ) ; const type = TypeBase . cloneForTypeAlias ( applySolvedTypeVars ( baseType , typeVarMap ) , baseType . typeAliasInfo . name , baseType . typeAliasInfo . fullName , baseType . typeAliasInfo . typeVarScopeId , baseType . typeAliasInfo . typeParameters , aliasTypeArgs ) ; return { type , node } ; } function getTypeFromIndexWithBaseType ( node , baseType , usage , flags ) { const typeAliasResult = createSpecializedTypeAlias ( node , baseType , flags ) ; if ( typeAliasResult ) { return typeAliasResult ; } if ( isTypeAliasPlaceholder ( baseType ) ) { const typeArgTypes = getTypeArgs ( node , flags ) . map ( ( t ) => convertToInstance ( t . type ) ) ; const type = TypeBase . cloneForTypeAlias ( baseType , baseType . details . recursiveTypeAliasName ! , '' , baseType . details . recursiveTypeAliasScopeId ! , undefined , typeArgTypes ) ; return { type , node } ; } let isIncomplete = false ; const type = mapSubtypesExpandTypeVars ( baseType , undefined , ( concreteSubtype , unexpandedSubtype ) => { if ( isAnyOrUnknown ( concreteSubtype ) ) { return concreteSubtype ; } if ( flags & EvaluatorFlags . ExpectingType ) { if ( isTypeVar ( unexpandedSubtype ) ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeVarNotSubscriptable ( ) . format ( { type : printType ( unexpandedSubtype ) , } ) , node . baseExpression ) ; getTypeArgs ( node , flags , false , false ) ; return UnknownType . create ( ) ; } } if ( isInstantiableClass ( concreteSubtype ) ) { if ( concreteSubtype . details . effectiveMetaclass && isInstantiableClass ( concreteSubtype . details . effectiveMetaclass ) && ! ClassType . isBuiltIn ( concreteSubtype . details . effectiveMetaclass , 'type' ) ) { const itemMethodType = getTypeFromClassMember ( node , concreteSubtype , getIndexAccessMagicMethodName ( usage ) , undefined , undefined , MemberAccessFlags . ConsiderMetaclassOnly ) ; if ( itemMethodType ) { return getTypeFromIndexedObjectOrClass ( node , concreteSubtype , usage ) . type ; } } if ( usage . method === 'set' ) { addError ( Localizer . Diagnostic . genericClassAssigned ( ) , node . baseExpression ) ; } else if ( usage . method === 'del' ) { addError ( Localizer . Diagnostic . genericClassDeleted ( ) , node . baseExpression ) ; } if ( ClassType . isSpecialBuiltIn ( concreteSubtype , 'Literal' ) ) { return createLiteralType ( node , flags ) ; } if ( ClassType . isBuiltIn ( concreteSubtype , 'InitVar' ) ) { const typeArgs = getTypeArgs ( node , flags ) ; if ( typeArgs . length === 1 ) { return typeArgs [ 0 ] . type ; } else { addError ( Localizer . Diagnostic . typeArgsMismatchOne ( ) . format ( { received : typeArgs . length } ) , node . baseExpression ) ; return UnknownType . create ( ) ; } } if ( ClassType . isEnumClass ( concreteSubtype ) ) { return ClassType . cloneAsInstance ( concreteSubtype ) ; } const isAnnotatedClass = isInstantiableClass ( concreteSubtype ) && ClassType . isBuiltIn ( concreteSubtype , 'Annotated' ) ; const hasCustomClassGetItem = isInstantiableClass ( concreteSubtype ) && ClassType . hasCustomClassGetItem ( concreteSubtype ) ; const isGenericClass = concreteSubtype . details . typeParameters ?. length > 0 || ClassType . isSpecialBuiltIn ( concreteSubtype ) || ClassType . isBuiltIn ( concreteSubtype , 'type' ) || ClassType . isPartiallyConstructed ( concreteSubtype ) ; const isFinalAnnotation = isInstantiableClass ( concreteSubtype ) && ClassType . isBuiltIn ( concreteSubtype , 'Final' ) ; const isClassVarAnnotation = isInstantiableClass ( concreteSubtype ) && ClassType . isBuiltIn ( concreteSubtype , 'ClassVar' ) ; let typeArgs = getTypeArgs ( node , flags , isAnnotatedClass , hasCustomClassGetItem || ! isGenericClass , isFinalAnnotation , isClassVarAnnotation ) ; if ( ! isAnnotatedClass ) { typeArgs = adjustTypeArgumentsForVariadicTypeVar ( typeArgs , concreteSubtype . details . typeParameters ) ; } if ( hasCustomClassGetItem ) { return concreteSubtype ; } if ( concreteSubtype . typeArguments ) { addError ( Localizer . Diagnostic . classAlreadySpecialized ( ) . format ( { type : printType ( convertToInstance ( concreteSubtype ) , true ) , } ) , node . baseExpression ) ; return concreteSubtype ; } return createSpecializedClassType ( concreteSubtype , typeArgs , flags , node ) ; } if ( isClassInstance ( concreteSubtype ) ) { const typeResult = getTypeFromIndexedObjectOrClass ( node , concreteSubtype , usage ) ; if ( typeResult . isIncomplete ) { isIncomplete = true ; } return typeResult . type ; } if ( isNever ( concreteSubtype ) ) { return UnknownType . create ( ) ; } if ( isNoneInstance ( concreteSubtype ) ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportOptionalSubscript , DiagnosticRule . reportOptionalSubscript , Localizer . Diagnostic . noneNotSubscriptable ( ) , node . baseExpression ) ; return UnknownType . create ( ) ; } if ( ! isUnbound ( concreteSubtype ) ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeNotSubscriptable ( ) . format ( { type : printType ( concreteSubtype ) } ) , node . baseExpression ) ; } return UnknownType . create ( ) ; } ) ; node . items . forEach ( ( item ) => { if ( ! isTypeCached ( item . valueExpression ) ) { getTypeOfExpression ( item . valueExpression , undefined , flags & EvaluatorFlags . AllowForwardReferences ) ; } } ) ; return { type , node , isIncomplete } ; } function makeTupleObject ( entryTypes , isUnspecifiedLength = false ) { if ( tupleClassType && isInstantiableClass ( tupleClassType ) ) { if ( isUnspecifiedLength ) { return convertToInstance ( specializeTupleClass ( tupleClassType , [ combineTypes ( entryTypes ) , AnyType . create ( true ) , ] ) ) ; } return convertToInstance ( specializeTupleClass ( tupleClassType , entryTypes ) ) ; } return UnknownType . create ( ) ; } function getIndexAccessMagicMethodName ( usage ) { if ( usage . method === 'get' ) { return '__getitem__' ; } else if ( usage . method === 'set' ) { return '__setitem__' ; } else { assert ( usage . method === 'del' ) ; return '__delitem__' ; } } function getTypeFromIndexedObjectOrClass ( node , baseType , usage ) { if ( isClassInstance ( baseType ) && ClassType . isTypedDictClass ( baseType ) ) { const typeFromTypedDict = getTypeFromIndexedTypedDict ( evaluatorInterface , node , baseType , usage ) ; if ( typeFromTypedDict ) { return typeFromTypedDict ; } } const magicMethodName = getIndexAccessMagicMethodName ( usage ) ; const itemMethodType = isClassInstance ( baseType ) ? getTypeFromObjectMember ( node , baseType , magicMethodName ) ?. type : getTypeFromClassMember ( node , baseType , magicMethodName , undefined , undefined , MemberAccessFlags . ConsiderMetaclassOnly ) ?. type ; if ( ! itemMethodType ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . methodNotDefinedOnType ( ) . format ( { name : magicMethodName , type : printType ( baseType ) , } ) , node . baseExpression ) ; return { node , type : UnknownType . create ( ) } ; } if ( node . items . length === 1 && ! node . trailingComma && ! node . items [ 0 ] . name && node . items [ 0 ] . argumentCategory === ArgumentCategory . Simple && isClassInstance ( baseType ) ) { const index0Expr = node . items [ 0 ] . valueExpression ; const valueType = getTypeOfExpression ( index0Expr ) . type ; if ( isClassInstance ( valueType ) && ClassType . isBuiltIn ( valueType , 'int' ) && isLiteralType ( valueType ) ) { const indexValue = valueType . literalValue as number ; const tupleType = getSpecializedTupleType ( baseType ) ; if ( tupleType && tupleType . tupleTypeArguments ) { if ( isOpenEndedTupleClass ( tupleType ) ) { return { node , type : tupleType . tupleTypeArguments [ 0 ] } ; } else if ( indexValue >= 0 && indexValue < tupleType . tupleTypeArguments . length ) { return { node , type : tupleType . tupleTypeArguments [ indexValue ] } ; } else if ( indexValue < 0 && tupleType . tupleTypeArguments . length + indexValue >= 0 ) { return { node , type : tupleType . tupleTypeArguments [ tupleType . tupleTypeArguments . length + indexValue ] , } ; } } } else if ( isClassInstance ( valueType ) && ClassType . isBuiltIn ( valueType , 'slice' ) ) { const tupleType = getSpecializedTupleType ( baseType ) ; if ( tupleType && tupleType . tupleTypeArguments && ! isOpenEndedTupleClass ( tupleType ) ) { if ( index0Expr . nodeType === ParseNodeType . Slice && ! index0Expr . stepValue ) { const getSliceParameter = ( expression , defaultValue ) => { let value = defaultValue ; if ( expression ) { const valType = getTypeOfExpression ( expression ) . type ; if ( isClassInstance ( valType ) && ClassType . isBuiltIn ( valType , 'int' ) && isLiteralType ( valType ) ) { value = valType . literalValue as number ; if ( value < 0 ) { value = tupleType . tupleTypeArguments ! . length + value ; } } else { value = - 1 ; } } return value ; } ; const startValue = getSliceParameter ( index0Expr . startValue , 0 ) ; const endValue = getSliceParameter ( index0Expr . endValue , tupleType . tupleTypeArguments . length ) ; if ( startValue >= 0 && endValue > 0 && endValue <= tupleType . tupleTypeArguments . length && tupleClassType && isInstantiableClass ( tupleClassType ) ) { return { node , type : ClassType . cloneAsInstance ( specializeTupleClass ( tupleClassType , tupleType . tupleTypeArguments . slice ( startValue , endValue ) ) ) , } ; } } } } } const positionalArgs = node . items . filter ( ( item ) => item . argumentCategory === ArgumentCategory . Simple && ! item . name ) ; const unpackedListArgs = node . items . filter ( ( item ) => item . argumentCategory === ArgumentCategory . UnpackedList ) ; const keywordArgs = node . items . filter ( ( item ) => item . argumentCategory === ArgumentCategory . Simple && ! ! item . name ) ; const unpackedDictArgs = node . items . filter ( ( item ) => item . argumentCategory === ArgumentCategory . UnpackedDictionary ) ; let positionalIndexType ; if ( positionalArgs . length === 1 && unpackedListArgs . length === 0 && ! node . trailingComma ) { positionalIndexType = getTypeOfExpression ( positionalArgs [ 0 ] . valueExpression ) . type ; } else if ( positionalArgs . length === 0 && unpackedListArgs . length === 0 ) { positionalIndexType = tupleClassType && isInstantiableClass ( tupleClassType ) ? convertToInstance ( specializeTupleClass ( tupleClassType , [ ] ) ) : UnknownType . create ( ) ; } else { const tupleEntries = [ ] ; positionalArgs . forEach ( ( arg ) => { tupleEntries . push ( getTypeOfExpression ( arg . valueExpression ) . type ) ; } ) ; unpackedListArgs . forEach ( ( arg ) => { const exprType = getTypeOfExpression ( arg . valueExpression ) . type ; const iterableType = getTypeFromIterator ( exprType , false , arg ) || UnknownType . create ( ) ; tupleEntries . push ( iterableType ) ; } ) ; positionalIndexType = makeTupleObject ( tupleEntries , unpackedListArgs . length > 0 ) ; } let argList = [ { argumentCategory : ArgumentCategory . Simple , type : positionalIndexType , } , ] ; if ( usage . method === 'set' ) { let setType = usage . setType || AnyType . create ( ) ; if ( isTypeVar ( setType ) && setType . details . constraints . length > 0 ) { const conditionFilter = isClassInstance ( baseType ) ? baseType . condition : undefined ; setType = makeTopLevelTypeVarsConcrete ( setType , conditionFilter ) ; } argList . push ( { argumentCategory : ArgumentCategory . Simple , type : setType , } ) ; } keywordArgs . forEach ( ( arg ) => { argList . push ( { argumentCategory : ArgumentCategory . Simple , valueExpression : arg . valueExpression , node : arg , name : arg . name , } ) ; } ) ; unpackedDictArgs . forEach ( ( arg ) => { argList . push ( { argumentCategory : ArgumentCategory . UnpackedDictionary , valueExpression : arg . valueExpression , node : arg , } ) ; } ) ; let callResult ; useSpeculativeMode ( node , ( ) => { callResult = validateCallArguments ( node , argList , itemMethodType ) ; if ( callResult . argumentErrors ) { if ( isClassInstance ( positionalIndexType ) && keywordArgs . length === 0 && unpackedDictArgs . length === 0 ) { const altArgList = [ ... argList ] ; altArgList [ 0 ] = { ... altArgList [ 0 ] } ; const indexMethod = getTypeFromObjectMember ( node , positionalIndexType , '__index__' ) ; if ( indexMethod ) { const intType = getBuiltInObject ( node , 'int' ) ; if ( isClassInstance ( intType ) ) { altArgList [ 0 ] . type = intType ; } } callResult = validateCallArguments ( node , altArgList , itemMethodType ) ; if ( ! callResult . argumentErrors ) { argList = altArgList ; } } } } ) ; callResult = validateCallArguments ( node , argList , itemMethodType ) ; return { node , type : callResult . returnType || UnknownType . create ( ) , isIncomplete : ! ! callResult . isTypeIncomplete , } ; } function getTypeArgs ( node , flags , isAnnotatedClass = false , hasCustomClassGetItem = false , isFinalAnnotation = false , isClassVarAnnotation = false ) { const typeArgs = [ ] ; let adjFlags = flags ; if ( isFinalAnnotation ) { adjFlags |= EvaluatorFlags . FinalDisallowed ; } else if ( isClassVarAnnotation ) { adjFlags |= EvaluatorFlags . ClassVarDisallowed ; } else { adjFlags &= ~ ( EvaluatorFlags . DoNotSpecialize | EvaluatorFlags . ParamSpecDisallowed | EvaluatorFlags . TypeVarTupleDisallowed | EvaluatorFlags . RequiredAllowed ) ; adjFlags |= EvaluatorFlags . ClassVarDisallowed ; } const getTypeArgTypeResult = ( expr , argIndex ) => { let typeResult ; if ( hasCustomClassGetItem || ( isAnnotatedClass && argIndex > 0 ) ) { typeResult = getTypeOfExpression ( expr , undefined , EvaluatorFlags . ParamSpecDisallowed | EvaluatorFlags . TypeVarTupleDisallowed | EvaluatorFlags . DoNotSpecialize | EvaluatorFlags . ClassVarDisallowed ) ; } else { typeResult = getTypeArg ( expr , adjFlags ) ; } return typeResult ; } ; if ( node . items . length === 1 && ! node . trailingComma && ! node . items [ 0 ] . name && node . items [ 0 ] . valueExpression . nodeType === ParseNodeType . Tuple && node . items [ 0 ] . valueExpression . expressions . length > 0 ) { node . items [ 0 ] . valueExpression . expressions . forEach ( ( item , index ) => { typeArgs . push ( getTypeArgTypeResult ( item , index ) ) ; } ) ; setTypeForNode ( node . items [ 0 ] . valueExpression ) ; } else { node . items . forEach ( ( arg , index ) => { const typeResult = getTypeArgTypeResult ( arg . valueExpression , index ) ; if ( arg . argumentCategory !== ArgumentCategory . Simple ) { if ( arg . argumentCategory === ArgumentCategory . UnpackedList && isVariadicTypeVar ( typeResult . type ) && ! typeResult . type . isVariadicUnpacked ) { typeResult . type = TypeVarType . cloneForUnpacked ( typeResult . type ) ; } else { addError ( Localizer . Diagnostic . unpackedArgInTypeArgument ( ) , arg . valueExpression ) ; typeResult . type = UnknownType . create ( ) ; } } if ( arg . name ) { addError ( Localizer . Diagnostic . keywordArgInTypeArgument ( ) , arg . valueExpression ) ; } typeArgs . push ( typeResult ) ; } ) ; } return typeArgs ; } function getTypeArg ( node , flags ) { let typeResult ; let adjustedFlags = flags | EvaluatorFlags . ExpectingType | EvaluatorFlags . ExpectingTypeAnnotation | EvaluatorFlags . ConvertEllipsisToAny | EvaluatorFlags . EvaluateStringLiteralAsType | EvaluatorFlags . FinalDisallowed | EvaluatorFlags . ClassVarDisallowed ; const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; if ( fileInfo . isStubFile ) { adjustedFlags |= EvaluatorFlags . AllowForwardReferences ; } if ( node . nodeType === ParseNodeType . List ) { typeResult = { type : UnknownType . create ( ) , typeList : node . entries . map ( ( entry ) => getTypeOfExpression ( entry , undefined , adjustedFlags ) ) , node , } ; setTypeForNode ( node ) ; } else { typeResult = getTypeOfExpression ( node , undefined , adjustedFlags ) ; if ( isClass ( typeResult . type ) && ClassType . isBuiltIn ( typeResult . type , 'Protocol' ) ) { addError ( Localizer . Diagnostic . protocolNotAllowedInTypeArgument ( ) , node ) ; } if ( isClass ( typeResult . type ) && ClassType . isBuiltIn ( typeResult . type , 'ClassVar' ) ) { addError ( Localizer . Diagnostic . protocolNotAllowedInTypeArgument ( ) , node ) ; } } return typeResult ; } function getTypeFromTuple ( node , expectedType , flags ) { if ( ( flags & EvaluatorFlags . ExpectingType ) !== 0 && node . expressions . length === 0 && ! expectedType ) { return { type : makeTupleObject ( [ ] ) , node , isEmptyTupleShorthand : true } ; } let effectiveExpectedType = expectedType ; if ( expectedType && isUnion ( expectedType ) ) { let matchingSubtype ; doForEachSubtype ( expectedType , ( subtype ) => { if ( ! matchingSubtype ) { const subtypeResult = useSpeculativeMode ( node , ( ) => { return getTypeFromTupleExpected ( node , subtype ) ; } ) ; if ( subtypeResult ) { matchingSubtype = subtype ; } } } ) ; effectiveExpectedType = matchingSubtype ; } if ( effectiveExpectedType ) { const result = getTypeFromTupleExpected ( node , effectiveExpectedType ) ; if ( result ) { return result ; } } return getTypeFromTupleInferred ( node , ! ! expectedType ) ; } function getTypeFromTupleExpected ( node , expectedType ) { expectedType = transformPossibleRecursiveTypeAlias ( expectedType ) ; if ( ! isClassInstance ( expectedType ) ) { return undefined ; } if ( ! tupleClassType || ! isInstantiableClass ( tupleClassType ) ) { return undefined ; } const expectedTypes = [ ] ; if ( isTupleClass ( expectedType ) && expectedType . tupleTypeArguments ) { if ( isOpenEndedTupleClass ( expectedType ) ) { const homogenousType = transformPossibleRecursiveTypeAlias ( expectedType . tupleTypeArguments [ 0 ] ) ; for ( let i = 0 ; i < node . expressions . length ; i ++ ) { expectedTypes . push ( homogenousType ) ; } } else { expectedType . tupleTypeArguments . forEach ( ( typeArg ) => { expectedTypes . push ( transformPossibleRecursiveTypeAlias ( typeArg ) ) ; } ) ; } } else { const tupleTypeVarMap = new TypeVarMap ( getTypeVarScopeId ( tupleClassType ) ) ; if ( ! populateTypeVarMapBasedOnExpectedType ( tupleClassType , expectedType , tupleTypeVarMap , getTypeVarScopesForNode ( node ) ) ) { return undefined ; } const specializedTuple = applySolvedTypeVars ( tupleClassType , tupleTypeVarMap ) as ClassType ; if ( ! specializedTuple . typeArguments || specializedTuple . typeArguments . length !== 1 ) { return undefined ; } const homogenousType = transformPossibleRecursiveTypeAlias ( specializedTuple . typeArguments [ 0 ] ) ; for ( let i = 0 ; i < node . expressions . length ; i ++ ) { expectedTypes . push ( homogenousType ) ; } } const entryTypeResults = node . expressions . map ( ( expr , index ) => getTypeOfExpression ( expr , index < expectedTypes . length ? expectedTypes [ index ] : undefined ) ) ; const expectedTypesContainLiterals = expectedTypes . some ( ( type ) => isLiteralTypeOrUnion ( type ) ) ; const type = convertToInstance ( specializeTupleClass ( tupleClassType , buildTupleTypesList ( entryTypeResults ) , true , ! expectedTypesContainLiterals ) ) ; return { type , node } ; } function getTypeFromTupleInferred ( node , useAny ) { const entryTypeResults = node . expressions . map ( ( expr ) => getTypeOfExpression ( expr , useAny ? AnyType . create ( ) : undefined ) ) ; const isIncomplete = entryTypeResults . some ( ( result ) => result . isIncomplete ) ; if ( ! tupleClassType || ! isInstantiableClass ( tupleClassType ) ) { return { type : UnknownType . create ( ) , node } ; } const type = convertToInstance ( specializeTupleClass ( tupleClassType , buildTupleTypesList ( entryTypeResults ) ) ) ; return { type , node , isIncomplete } ; } function buildTupleTypesList ( entryTypeResults ) { const entryTypes = [ ] ; let isOpenEnded = false ; for ( const typeResult of entryTypeResults ) { if ( typeResult . unpackedType ) { if ( isClassInstance ( typeResult . unpackedType ) && isTupleClass ( typeResult . unpackedType ) ) { const typeArgs = typeResult . unpackedType . tupleTypeArguments ; if ( ! typeArgs || isOpenEndedTupleClass ( typeResult . unpackedType ) ) { entryTypes . push ( typeResult . type ) ; isOpenEnded = true ; } else { entryTypes . push ( ... typeArgs ) ; } } else { entryTypes . push ( typeResult . type ) ; isOpenEnded = true ; } } else { entryTypes . push ( typeResult . type ) ; } } if ( isOpenEnded ) { return [ combineTypes ( entryTypes ) , AnyType . create ( true ) ] ; } return entryTypes ; } function getTypeFromCall ( node , expectedType ) { const baseTypeResult = getTypeOfExpression ( node . leftExpression , undefined , EvaluatorFlags . DoNotSpecialize ) ; const argList = node . arguments . map ( ( arg ) => { const functionArg = { valueExpression : arg . valueExpression , argumentCategory : arg . argumentCategory , node : arg , name : arg . name , } ; return functionArg ; } ) ; let returnResult = { node , type : UnknownType . create ( ) } ; if ( ! isTypeAliasPlaceholder ( baseTypeResult . type ) ) { if ( node . leftExpression . nodeType === ParseNodeType . Name && node . leftExpression . value === 'super' ) { returnResult = getTypeFromSuperCall ( node ) ; } else if ( isAnyOrUnknown ( baseTypeResult . type ) && node . leftExpression . nodeType === ParseNodeType . Name && node . leftExpression . value === 'reveal_type' ) { if ( node . arguments . length === 1 && node . arguments [ 0 ] . argumentCategory === ArgumentCategory . Simple && node . arguments [ 0 ] . name === undefined ) { returnResult = getTypeFromRevealType ( node ) ; } else { addError ( Localizer . Diagnostic . revealTypeArgs ( ) , node ) ; } } else if ( isAnyOrUnknown ( baseTypeResult . type ) && node . leftExpression . nodeType === ParseNodeType . Name && node . leftExpression . value === 'reveal_locals' ) { if ( node . arguments . length === 0 ) { returnResult . type = getTypeFromRevealLocals ( node ) ; } else { addError ( Localizer . Diagnostic . revealLocalsArgs ( ) , node ) ; } } else { const callResult = validateCallArguments ( node , argList , baseTypeResult . type , undefined , false , expectedType ) ; returnResult . type = callResult . returnType || UnknownType . create ( ) ; if ( isUnion ( returnResult . type ) ) { returnResult . type = removeNoReturnFromUnion ( returnResult . type ) ; } if ( callResult . argumentErrors ) { returnResult . typeErrors = true ; if ( expectedType ) { returnResult . isIncomplete = true ; } } if ( callResult . isTypeIncomplete ) { returnResult . isIncomplete = true ; } } if ( baseTypeResult . isIncomplete ) { returnResult . isIncomplete = true ; } } else { returnResult . isIncomplete = true ; } const isCyclicalTypeVarCall = isInstantiableClass ( baseTypeResult . type ) && ClassType . isBuiltIn ( baseTypeResult . type , 'TypeVar' ) && AnalyzerNodeInfo . getFileInfo ( node ) . isTypingStubFile ; if ( ! isCyclicalTypeVarCall ) { argList . forEach ( ( arg ) => { if ( arg . valueExpression && arg . valueExpression . nodeType !== ParseNodeType . StringList && ! isTypeCached ( arg . valueExpression ) ) { getTypeOfExpression ( arg . valueExpression ) ; } } ) ; } return returnResult ; } function getTypeFromRevealType ( node ) { const typeResult = getTypeOfExpression ( node . arguments [ 0 ] . valueExpression ) ; const type = typeResult . type ; const exprString = ParseTreeUtils . printExpression ( node . arguments [ 0 ] . valueExpression ) ; const typeString = printType ( type , true ) ; addInformation ( Localizer . DiagnosticAddendum . typeOfSymbol ( ) . format ( { name : exprString , type : typeString } ) , node . arguments [ 0 ] ) ; const strType = getBuiltInType ( node , 'str' ) ; let returnType = AnyType . create ( ) ; if ( isInstantiableClass ( strType ) ) { returnType = ClassType . cloneAsInstance ( ClassType . cloneWithLiteral ( strType , typeString ) ) ; } return { node , type : returnType , isIncomplete : typeResult . isIncomplete , } ; } function getTypeFromRevealLocals ( node ) { let curNode = node ; let scope ; while ( curNode ) { scope = ScopeUtils . getScopeForNode ( curNode ) ; if ( scope && scope . type !== ScopeType . ListComprehension ) { break ; } curNode = curNode . parent ; } const infoMessages = [ ] ; if ( scope ) { scope . symbolTable . forEach ( ( symbol , name ) => { if ( ! symbol . isIgnoredForProtocolMatch ( ) ) { const typeOfSymbol = getEffectiveTypeOfSymbol ( symbol ) ; infoMessages . push ( Localizer . DiagnosticAddendum . typeOfSymbol ( ) . format ( { name , type : printType ( typeOfSymbol , true ) , } ) ) ; } } ) ; } if ( infoMessages . length > 0 ) { addInformation ( infoMessages . join ( '\n' ) , node ) ; } else { addInformation ( Localizer . Diagnostic . revealLocalsNone ( ) , node ) ; } return NoneType . createInstance ( ) ; } function getTypeFromSuperCall ( node ) { if ( node . arguments . length > 2 ) { addError ( Localizer . Diagnostic . superCallArgCount ( ) , node . arguments [ 2 ] ) ; } let targetClassType ; if ( node . arguments . length > 0 ) { targetClassType = getTypeOfExpression ( node . arguments [ 0 ] . valueExpression ) . type ; const concreteTargetClassType = makeTopLevelTypeVarsConcrete ( targetClassType ) ; if ( ! isAnyOrUnknown ( concreteTargetClassType ) && ! isInstantiableClass ( concreteTargetClassType ) ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . superCallFirstArg ( ) . format ( { type : printType ( targetClassType ) } ) , node . arguments [ 0 ] . valueExpression ) ; } } else { const enclosingClass = ParseTreeUtils . getEnclosingClass ( node ) ; if ( enclosingClass ) { const classTypeInfo = getTypeOfClass ( enclosingClass ) ; targetClassType = classTypeInfo ? classTypeInfo . classType : UnknownType . create ( ) ; } else { addError ( Localizer . Diagnostic . superCallZeroArgForm ( ) , node . leftExpression ) ; targetClassType = UnknownType . create ( ) ; } } let bindToType ; if ( node . arguments . length > 1 ) { const secondArgType = makeTopLevelTypeVarsConcrete ( getTypeOfExpression ( node . arguments [ 1 ] . valueExpression ) . type ) ; let reportError = false ; if ( isAnyOrUnknown ( secondArgType ) ) { } else if ( isClassInstance ( secondArgType ) ) { if ( isInstantiableClass ( targetClassType ) ) { if ( ! derivesFromClassRecursive ( ClassType . cloneAsInstantiable ( secondArgType ) , targetClassType , true ) ) { reportError = true ; } } bindToType = secondArgType ; } else if ( isInstantiableClass ( secondArgType ) ) { if ( isInstantiableClass ( targetClassType ) ) { if ( ! derivesFromClassRecursive ( secondArgType , targetClassType , true ) ) { reportError = true ; } } bindToType = secondArgType ; } else { reportError = true ; } if ( reportError ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . superCallSecondArg ( ) . format ( { type : printType ( targetClassType ) } ) , node . arguments [ 1 ] . valueExpression ) ; } } else { const enclosingMethod = ParseTreeUtils . getEnclosingFunction ( node ) ; let implicitBindToType ; if ( enclosingMethod ) { const methodTypeInfo = getTypeOfFunction ( enclosingMethod ) ; if ( methodTypeInfo ) { const methodType = methodTypeInfo . functionType ; if ( FunctionType . isClassMethod ( methodType ) ) { if ( methodType . details . parameters . length > 0 && methodType . details . parameters [ 0 ] . hasDeclaredType ) { implicitBindToType = makeTopLevelTypeVarsConcrete ( methodType . details . parameters [ 0 ] . type ) ; } } else if ( FunctionType . isInstanceMethod ( methodType ) ) { if ( methodType . details . parameters . length > 0 && methodType . details . parameters [ 0 ] . hasDeclaredType ) { implicitBindToType = makeTopLevelTypeVarsConcrete ( convertToInstantiable ( methodType . details . parameters [ 0 ] . type ) ) ; } } } } if ( implicitBindToType && isInstantiableClass ( implicitBindToType ) ) { bindToType = implicitBindToType ; } else if ( isInstantiableClass ( targetClassType ) ) { bindToType = targetClassType ; } } let resultIsInstance = true ; const enclosingMethod = ParseTreeUtils . getEnclosingFunction ( node ) ; if ( enclosingMethod ) { const methodType = getTypeOfFunction ( enclosingMethod ) ; if ( methodType ) { if ( FunctionType . isStaticMethod ( methodType . functionType ) || FunctionType . isConstructorMethod ( methodType . functionType ) || FunctionType . isClassMethod ( methodType . functionType ) ) { resultIsInstance = false ; } } } const parentNode = node . parent ! ; if ( parentNode . nodeType === ParseNodeType . MemberAccess ) { const memberName = parentNode . memberName . value ; const lookupResults = lookUpClassMember ( targetClassType , memberName , ClassMemberLookupFlags . SkipOriginalClass ) ; if ( lookupResults && isInstantiableClass ( lookupResults . classType ) ) { return { type : resultIsInstance ? ClassType . cloneAsInstance ( lookupResults . classType ) : lookupResults . classType , node , bindToType : resultIsInstance && bindToType && isInstantiableClass ( bindToType ) ? ClassType . cloneAsInstance ( bindToType ) : bindToType , } ; } } if ( isInstantiableClass ( targetClassType ) ) { if ( targetClassType . details . mro . some ( ( mroBase ) => isAnyOrUnknown ( mroBase ) ) ) { return { type : UnknownType . create ( ) , node , } ; } const baseClasses = targetClassType . details . baseClasses ; if ( baseClasses . length > 0 ) { const baseClassType = baseClasses [ 0 ] ; if ( isInstantiableClass ( baseClassType ) ) { return { type : resultIsInstance ? ClassType . cloneAsInstance ( baseClassType ) : baseClassType , node , } ; } } } return { type : UnknownType . create ( ) , node , } ; } function validateOverloadsWithExpandedTypes ( errorNode , expandedArgTypes , argParamMatches , typeVarMap , skipUnknownArgCheck , expectedType ) { const returnTypes = [ ] ; const matchedOverloads = [ ] ; let isTypeIncomplete = false ; for ( let expandedTypesIndex = 0 ; expandedTypesIndex < expandedArgTypes . length ; expandedTypesIndex ++ ) { let matchedOverload ; const argTypeOverride = expandedArgTypes [ expandedTypesIndex ] ; const hasArgTypeOverride = argTypeOverride . some ( ( a ) => a !== undefined ) ; for ( let overloadIndex = 0 ; overloadIndex < argParamMatches . length ; overloadIndex ++ ) { const overload = argParamMatches [ overloadIndex ] . overload ; let matchResults = argParamMatches [ overloadIndex ] ; if ( hasArgTypeOverride ) { matchResults = { ... argParamMatches [ overloadIndex ] } ; matchResults . argParams = matchResults . argParams . map ( ( argParam , argIndex ) => { if ( ! argTypeOverride [ argIndex ] ) { return argParam ; } const argParamCopy = { ... argParam } ; argParamCopy . argType = argTypeOverride [ argIndex ] ; return argParamCopy ; } ) ; } const effectiveTypeVarMap = typeVarMap ? typeVarMap . clone ( ) : new TypeVarMap ( getTypeVarScopeId ( overload ) ) ; effectiveTypeVarMap . addSolveForScope ( getTypeVarScopeId ( overload ) ) ; const callResult = useSpeculativeMode ( errorNode , ( ) => { return validateFunctionArgumentTypes ( errorNode , matchResults , effectiveTypeVarMap , true , expectedType ) ; } ) ; if ( callResult . isTypeIncomplete ) { isTypeIncomplete = true ; } if ( ! callResult . argumentErrors && callResult . returnType ) { matchedOverload = overload ; matchedOverloads . push ( { overload : matchedOverload , matchResults , typeVarMap : effectiveTypeVarMap } ) ; returnTypes . push ( callResult . returnType ) ; break ; } } if ( ! matchedOverload ) { return { argumentErrors : true , isTypeIncomplete } ; } } if ( typeVarMap ) { for ( let expandedTypesIndex = 0 ; expandedTypesIndex < expandedArgTypes . length ; expandedTypesIndex ++ ) { const overload = matchedOverloads [ expandedTypesIndex ] . overload ; const matchResults = matchedOverloads [ expandedTypesIndex ] . matchResults ; useSpeculativeMode ( errorNode , ( ) => { typeVarMap . addSolveForScope ( getTypeVarScopeId ( overload ) ) ; typeVarMap . unlock ( ) ; return validateFunctionArgumentTypes ( errorNode , matchResults , typeVarMap , true , expectedType ) ; } ) ; } } matchedOverloads [ 0 ] . typeVarMap . unlock ( ) ; const finalCallResult = validateFunctionArgumentTypes ( errorNode , matchedOverloads [ 0 ] . matchResults , matchedOverloads [ 0 ] . typeVarMap , skipUnknownArgCheck , expectedType ) ; if ( finalCallResult . isTypeIncomplete ) { isTypeIncomplete = true ; } return { argumentErrors : false , returnType : combineTypes ( returnTypes ) , isTypeIncomplete , specializedInitSelfType : finalCallResult . specializedInitSelfType , } ; } function getBestOverloadForArguments ( errorNode , type , argList ) { let overloadIndex = 0 ; let matches = [ ] ; type . overloads . forEach ( ( overload ) => { useSpeculativeMode ( errorNode , ( ) => { if ( FunctionType . isOverloaded ( overload ) ) { const matchResults = matchFunctionArgumentsToParameters ( errorNode , argList , overload , overloadIndex ) ; if ( ! matchResults . argumentErrors ) { matches . push ( matchResults ) ; } overloadIndex ++ ; } } ) ; } ) ; matches = sortOverloadsByBestMatch ( matches ) ; let winningOverloadIndex ; matches . forEach ( ( match , matchIndex ) => { if ( winningOverloadIndex === undefined ) { useSpeculativeMode ( errorNode , ( ) => { const callResult = validateFunctionArgumentTypes ( errorNode , match , new TypeVarMap ( getTypeVarScopeId ( match . overload ) ) , true , undefined ) ; if ( callResult && ! callResult . argumentErrors ) { winningOverloadIndex = matchIndex ; } } ) ; } } ) ; return winningOverloadIndex === undefined ? undefined : matches [ winningOverloadIndex ] . overload ; } function sortOverloadsByBestMatch ( matches ) { return matches . sort ( ( a , b ) => { if ( a . relevance !== b . relevance ) { return b . relevance - a . relevance ; } return a . overloadIndex - b . overloadIndex ; } ) ; } function validateOverloadedFunctionArguments ( errorNode , argList , type , typeVarMap , skipUnknownArgCheck , expectedType ) { let filteredMatchResults = [ ] ; let contextFreeArgTypes = [ ] ; useSpeculativeMode ( errorNode , ( ) => { let overloadIndex = 0 ; type . overloads . forEach ( ( overload ) => { if ( FunctionType . isOverloaded ( overload ) ) { const matchResults = matchFunctionArgumentsToParameters ( errorNode , argList , overload , overloadIndex ) ; if ( ! matchResults . argumentErrors ) { filteredMatchResults . push ( matchResults ) ; } overloadIndex ++ ; } } ) ; contextFreeArgTypes = argList . map ( ( arg ) => arg . type ? arg . type : arg . valueExpression ? getTypeOfExpression ( arg . valueExpression ) . type : AnyType . create ( ) ) ; } ) ; filteredMatchResults = sortOverloadsByBestMatch ( filteredMatchResults ) ; if ( filteredMatchResults . length === 0 ) { if ( ! isDiagnosticSuppressedForNode ( errorNode ) ) { const functionName = type . overloads [ 0 ] . details . name || '<anonymous function>' ; const diagAddendum = new DiagnosticAddendum ( ) ; const argTypes = argList . map ( ( t ) => printType ( getTypeForArgument ( t ) . type ) ) ; diagAddendum . addMessage ( Localizer . DiagnosticAddendum . argumentTypes ( ) . format ( { types : argTypes . join ( ', ' ) } ) ) ; addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . noOverload ( ) . format ( { name : functionName } ) + diagAddendum . getString ( ) , errorNode ) ; } return { argumentErrors : true , isTypeIncomplete : false } ; } const evaluateUsingLastMatchingOverload = ( skipUnknownArgCheck ) => { const lastMatch = filteredMatchResults . reduce ( ( previous , current ) => { return current . overloadIndex > previous . overloadIndex ? current : previous ; } ) ; const effectiveTypeVarMap = typeVarMap ?? new TypeVarMap ( ) ; effectiveTypeVarMap . addSolveForScope ( getTypeVarScopeId ( lastMatch . overload ) ) ; effectiveTypeVarMap . unlock ( ) ; return validateFunctionArgumentTypes ( errorNode , lastMatch , effectiveTypeVarMap , skipUnknownArgCheck , expectedType ) ; } ; if ( filteredMatchResults . length === 1 ) { return evaluateUsingLastMatchingOverload ( false ) ; } let expandedArgTypes = [ argList . map ( ( arg ) => undefined ) ] ; let isTypeIncomplete = false ; while ( true ) { const callResult = validateOverloadsWithExpandedTypes ( errorNode , expandedArgTypes , filteredMatchResults , typeVarMap , skipUnknownArgCheck , expectedType ) ; if ( callResult . isTypeIncomplete ) { isTypeIncomplete = true ; } if ( ! callResult . argumentErrors ) { return callResult ; } expandedArgTypes = expandArgumentUnionTypes ( contextFreeArgTypes , expandedArgTypes ) ; if ( ! expandedArgTypes || expandedArgTypes . length > maxOverloadUnionExpansionCount ) { break ; } } if ( ! isDiagnosticSuppressedForNode ( errorNode ) && ! isTypeIncomplete ) { const result = evaluateUsingLastMatchingOverload ( true ) ; result . returnType = UnknownType . create ( ) ; return result ; } return { argumentErrors : true , isTypeIncomplete : false } ; } function expandArgumentUnionTypes ( contextFreeArgTypes , expandedArgTypes ) { let indexToExpand = contextFreeArgTypes . length - 1 ; while ( indexToExpand >= 0 && ! expandedArgTypes [ 0 ] [ indexToExpand ] ) { indexToExpand -- ; } indexToExpand ++ ; if ( indexToExpand >= contextFreeArgTypes . length ) { return undefined ; } let unionToExpand ; while ( indexToExpand < contextFreeArgTypes . length ) { const argType = contextFreeArgTypes [ indexToExpand ] ; if ( isUnion ( argType ) ) { unionToExpand = argType ; break ; } indexToExpand ++ ; } if ( ! unionToExpand ) { return undefined ; } const newExpandedArgTypes = [ ] ; expandedArgTypes . forEach ( ( preExpandedTypes ) => { doForEachSubtype ( unionToExpand ! , ( subtype ) => { const expandedTypes = [ ... preExpandedTypes ] ; expandedTypes [ indexToExpand ] = subtype ; newExpandedArgTypes . push ( expandedTypes ) ; } ) ; } ) ; return newExpandedArgTypes ; } function validateConstructorArguments ( errorNode , argList , type , skipUnknownArgCheck , expectedType ) { let validatedTypes = false ; let returnType ; let reportedErrors = false ; let isTypeIncomplete = false ; let usedMetaclassCallMethod = false ; const skipConstructorCheck = ( type ) => { return isFunction ( type ) && FunctionType . isSkipConstructorCheck ( type ) ; } ; const initMethodType = getTypeFromObjectMember ( errorNode , ClassType . cloneAsInstance ( type ) , '__init__' , { method : 'get' } , undefined , MemberAccessFlags . SkipObjectBaseClass | MemberAccessFlags . SkipAttributeAccessOverride ) ?. type ; if ( initMethodType && ! skipConstructorCheck ( initMethodType ) ) { if ( expectedType ) { returnType = mapSubtypes ( expectedType , ( expectedSubType ) => { expectedSubType = transformPossibleRecursiveTypeAlias ( expectedSubType ) ; const typeVarMap = new TypeVarMap ( getTypeVarScopeId ( type ) ) ; if ( populateTypeVarMapBasedOnExpectedType ( type , expectedSubType , typeVarMap , getTypeVarScopesForNode ( errorNode ) ) ) { let callResult ; useSpeculativeMode ( errorNode , ( ) => { callResult = validateCallArguments ( errorNode , argList , initMethodType , typeVarMap . clone ( ) , skipUnknownArgCheck , NoneType . createInstance ( ) ) ; } ) ; if ( ! callResult ?. argumentErrors ) { const callResult = validateCallArguments ( errorNode , argList , initMethodType , typeVarMap , skipUnknownArgCheck , NoneType . createInstance ( ) ) ; if ( callResult . isTypeIncomplete ) { isTypeIncomplete = true ; } return applyExpectedSubtypeForConstructor ( type , expectedSubType , typeVarMap ) ; } } return undefined ; } ) ; if ( isNever ( returnType ) ) { returnType = undefined ; } } if ( ! returnType ) { const typeVarMap = type . typeArguments ? buildTypeVarMapFromSpecializedClass ( type , false ) : new TypeVarMap ( getTypeVarScopeId ( type ) ) ; typeVarMap . addSolveForScope ( getTypeVarScopeId ( initMethodType ) ) ; const callResult = validateCallArguments ( errorNode , argList , initMethodType , typeVarMap , skipUnknownArgCheck ) ; if ( ! callResult . argumentErrors ) { let adjustedClassType = type ; if ( callResult . specializedInitSelfType && isClassInstance ( callResult . specializedInitSelfType ) && ClassType . isSameGenericClass ( callResult . specializedInitSelfType , type ) ) { adjustedClassType = ClassType . cloneAsInstantiable ( callResult . specializedInitSelfType ) ; } returnType = applyExpectedTypeForConstructor ( adjustedClassType , undefined , typeVarMap ) ; if ( callResult . isTypeIncomplete ) { isTypeIncomplete = true ; } } else { reportedErrors = true ; } } validatedTypes = true ; skipUnknownArgCheck = true ; } if ( ! reportedErrors ) { const metaclass = type . details . effectiveMetaclass ; let constructorMethodInfo ; if ( metaclass && isInstantiableClass ( metaclass ) && ! ClassType . isSameGenericClass ( metaclass , type ) ) { constructorMethodInfo = getTypeFromClassMemberName ( errorNode , metaclass , '__call__' , { method : 'get' } , undefined , MemberAccessFlags . ConsiderMetaclassOnly | MemberAccessFlags . SkipTypeBaseClass , type ) ; if ( constructorMethodInfo ) { usedMetaclassCallMethod = true ; } } if ( ! constructorMethodInfo ) { constructorMethodInfo = getTypeFromClassMemberName ( errorNode , type , '__new__' , { method : 'get' } , undefined , MemberAccessFlags . AccessClassMembersOnly | MemberAccessFlags . SkipObjectBaseClass | MemberAccessFlags . TreatConstructorAsClassMethod , type ) ; } if ( constructorMethodInfo && ! skipConstructorCheck ( constructorMethodInfo . type ) ) { const typeVarMap = new TypeVarMap ( getTypeVarScopeId ( type ) ) ; if ( type . typeAliasInfo ) { typeVarMap . addSolveForScope ( type . typeAliasInfo . typeVarScopeId ) ; } typeVarMap . addSolveForScope ( getTypeVarScopeId ( constructorMethodInfo . type ) ) ; const callResult = validateCallArguments ( errorNode , argList , constructorMethodInfo . type , typeVarMap , skipUnknownArgCheck ) ; if ( callResult . argumentErrors ) { reportedErrors = true ; } else { let newReturnType = callResult . returnType ; if ( callResult . isTypeIncomplete ) { isTypeIncomplete = true ; } if ( newReturnType ) { if ( isClassInstance ( newReturnType ) && ClassType . isSameGenericClass ( newReturnType , type ) ) { if ( ( ! isPartlyUnknown ( newReturnType ) && ! requiresSpecialization ( newReturnType ) ) || returnType === undefined ) { if ( isClassInstance ( newReturnType ) && ClassType . isTupleClass ( newReturnType ) && ! newReturnType . tupleTypeArguments && newReturnType . typeArguments && newReturnType . typeArguments . length === 1 ) { newReturnType = specializeTupleClass ( newReturnType , [ newReturnType . typeArguments [ 0 ] , AnyType . create ( true ) , ] ) ; } returnType = newReturnType ; } } else if ( ! returnType && ! isUnknown ( newReturnType ) ) { returnType = newReturnType ; } } } if ( ! returnType ) { returnType = applyExpectedTypeForConstructor ( type , expectedType , typeVarMap ) ; } else if ( isClassInstance ( returnType ) && isTupleClass ( returnType ) && ! returnType . tupleTypeArguments ) { returnType = applyExpectedTypeForTupleConstructor ( returnType , expectedType ) ; } validatedTypes = true ; } } if ( ! validatedTypes ) { argList . forEach ( ( arg ) => { if ( arg . valueExpression && ! speculativeTypeTracker . isSpeculative ( arg . valueExpression ) ) { getTypeOfExpression ( arg . valueExpression ) ; } } ) ; } if ( ! validatedTypes && argList . length > 0 ) { const isCustomMetaclass = ! ! type . details . effectiveMetaclass && isInstantiableClass ( type . details . effectiveMetaclass ) && ! ClassType . isBuiltIn ( type . details . effectiveMetaclass ) ; if ( ! isCustomMetaclass && ! usedMetaclassCallMethod ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( errorNode ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . constructorNoArgs ( ) . format ( { type : type . aliasName || type . details . name } ) , errorNode ) ; } } if ( ! returnType ) { const typeVarMap = new TypeVarMap ( getTypeVarScopeId ( type ) ) ; if ( expectedType ) { populateTypeVarMapBasedOnExpectedType ( type , expectedType , typeVarMap , getTypeVarScopesForNode ( errorNode ) ) ; } returnType = applyExpectedTypeForConstructor ( type , expectedType , typeVarMap ) ; } if ( ! reportedErrors ) { const transformed = applyConstructorTransform ( evaluatorInterface , errorNode , argList , type , { argumentErrors : reportedErrors , returnType , isTypeIncomplete , } ) ; returnType = transformed . returnType ; if ( transformed . isTypeIncomplete ) { isTypeIncomplete = true ; } if ( transformed . argumentErrors ) { reportedErrors = true ; } } const result = { argumentErrors : reportedErrors , returnType , isTypeIncomplete } ; return result ; } function applyExpectedSubtypeForConstructor ( type , expectedSubtype , typeVarMap ) { const specializedType = applySolvedTypeVars ( ClassType . cloneAsInstance ( type ) , typeVarMap , true ) ; if ( ! canAssignType ( expectedSubtype , specializedType ) ) { return undefined ; } if ( isAny ( expectedSubtype ) ) { return expectedSubtype ; } return specializedType ; } function applyExpectedTypeForConstructor ( type , expectedType , typeVarMap ) { if ( expectedType ) { const specializedExpectedType = mapSubtypes ( expectedType , ( expectedSubtype ) => { return applyExpectedSubtypeForConstructor ( type , expectedSubtype , typeVarMap ) ; } ) ; if ( ! isNever ( specializedExpectedType ) ) { return specializedExpectedType ; } } const specializedType = applySolvedTypeVars ( type , typeVarMap , true ) as ClassType ; return ClassType . cloneAsInstance ( specializedType ) ; } function applyExpectedTypeForTupleConstructor ( type , expectedType ) { let specializedType = type ; if ( expectedType && isClassInstance ( expectedType ) && isTupleClass ( expectedType ) && expectedType . tupleTypeArguments ) { specializedType = specializeTupleClass ( type , expectedType . tupleTypeArguments ) ; } return specializedType ; } function populateTypeVarMapBasedOnExpectedType ( type , expectedType , typeVarMap , liveTypeVarScopes ) { if ( isAny ( expectedType ) ) { type . details . typeParameters . forEach ( ( typeParam ) => { typeVarMap . setTypeVarType ( typeParam , expectedType ) ; } ) ; return true ; } if ( ! isClassInstance ( expectedType ) ) { return false ; } const expectedTypeArgs = expectedType . typeArguments ; if ( ! expectedTypeArgs ) { return canAssignType ( type , ClassType . cloneAsInstantiable ( expectedType ) , undefined , typeVarMap ) ; } if ( ClassType . isSameGenericClass ( expectedType , type ) ) { const sameClassTypeVarMap = buildTypeVarMapFromSpecializedClass ( expectedType ) ; sameClassTypeVarMap . getTypeVars ( ) . forEach ( ( entry ) => { const typeVarType = sameClassTypeVarMap . getTypeVarType ( entry . typeVar ) ; if ( typeVarType ) { if ( ! isTypeVar ( typeVarType ) || typeVarType . scopeId !== type . details . typeVarScopeId ) { typeVarMap . setTypeVarType ( entry . typeVar , entry . typeVar . details . variance === Variance . Covariant ? undefined : typeVarType , entry . typeVar . details . variance === Variance . Contravariant ? undefined : typeVarType , entry . retainLiteral ) ; } } } ) ; return true ; } const expectedTypeScopeId = getTypeVarScopeId ( expectedType ) ; const synthExpectedTypeArgs = ClassType . getTypeParameters ( expectedType ) . map ( ( typeParam , index ) => { const typeVar = TypeVarType . createInstance ( `__dest${ index }` ) ; typeVar . details . isSynthesized = true ; typeVar . details . variance = typeParam . details . variance ; typeVar . scopeId = expectedTypeScopeId ; return typeVar ; } ) ; const genericExpectedType = ClassType . cloneForSpecialization ( ClassType . cloneAsInstantiable ( expectedType ) , synthExpectedTypeArgs , true ) ; const typeArgs = ClassType . getTypeParameters ( type ) . map ( ( _ , index ) => { const typeVar = TypeVarType . createInstance ( `__source${ index }` ) ; typeVar . details . isSynthesized = true ; typeVar . details . synthesizedIndex = index ; typeVar . details . isExemptFromBoundCheck = true ; return typeVar ; } ) ; const specializedType = ClassType . cloneForSpecialization ( type , typeArgs , true ) ; const syntheticTypeVarMap = new TypeVarMap ( expectedTypeScopeId ) ; if ( canAssignType ( genericExpectedType , specializedType , undefined , syntheticTypeVarMap ) ) { let isResultValid = true ; synthExpectedTypeArgs . forEach ( ( typeVar , index ) => { const synthTypeVar = syntheticTypeVarMap . getTypeVarType ( typeVar ) ; if ( synthTypeVar && isTypeVar ( synthTypeVar ) && synthTypeVar . details . isSynthesized && synthTypeVar . details . synthesizedIndex !== undefined ) { const targetTypeVar = ClassType . getTypeParameters ( specializedType ) [ synthTypeVar . details . synthesizedIndex ] ; if ( index < expectedTypeArgs . length ) { let expectedTypeArgValue = expectedTypeArgs [ index ] ; if ( liveTypeVarScopes ) { expectedTypeArgValue = transformExpectedTypeForConstructor ( expectedTypeArgValue , typeVarMap , liveTypeVarScopes ) ; } if ( expectedTypeArgValue ) { typeVarMap . setTypeVarType ( targetTypeVar , typeVar . details . variance === Variance . Covariant ? undefined : expectedTypeArgValue , typeVar . details . variance === Variance . Contravariant ? undefined : expectedTypeArgValue ) ; } else { isResultValid = false ; } } } } ) ; return isResultValid ; } return false ; } function validateCallArguments ( errorNode , argList , callType , typeVarMap ? , skipUnknownArgCheck = false , expectedType ? , recursionCount = 0 ) { let argumentErrors = false ; let isTypeIncomplete = false ; let specializedInitSelfType ; if ( recursionCount > maxTypeRecursionCount ) { return { returnType : UnknownType . create ( ) , argumentErrors : true } ; } if ( TypeBase . isSpecialForm ( callType ) ) { const exprNode = errorNode . nodeType === ParseNodeType . Call ? errorNode . leftExpression : errorNode ; addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeNotCallable ( ) . format ( { expression : ParseTreeUtils . printExpression ( exprNode ) , type : printType ( callType , true ) , } ) , exprNode ) ; return { returnType : UnknownType . create ( ) , argumentErrors : true } ; } const returnType = mapSubtypesExpandTypeVars ( callType , undefined , ( expandedSubtype , unexpandedSubtype ) => { switch ( expandedSubtype . category ) { case TypeCategory . Unknown : case TypeCategory . Any : { argList . forEach ( ( arg ) => { if ( arg . valueExpression && ! speculativeTypeTracker . isSpeculative ( arg . valueExpression ) ) { getTypeForArgument ( arg ) ; } } ) ; return expandedSubtype ; } case TypeCategory . Function : { if ( expandedSubtype . details . builtInName === 'namedtuple' ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportUntypedNamedTuple , DiagnosticRule . reportUntypedNamedTuple , Localizer . Diagnostic . namedTupleNoTypes ( ) , errorNode ) ; return createNamedTupleType ( evaluatorInterface , errorNode , argList , false ) ; } let effectiveTypeVarMap = typeVarMap ; if ( ! effectiveTypeVarMap ) { effectiveTypeVarMap = new TypeVarMap ( getTypeVarScopeId ( expandedSubtype ) ) ; if ( ! effectiveTypeVarMap . getSolveForScopes ( ) && FunctionType . isConstructorMethod ( expandedSubtype ) ) { effectiveTypeVarMap . addSolveForScope ( WildcardTypeVarScopeId ) ; } } const functionResult = validateFunctionArguments ( errorNode , argList , expandedSubtype , effectiveTypeVarMap , skipUnknownArgCheck , expectedType ) ; if ( functionResult . isTypeIncomplete ) { isTypeIncomplete = true ; } if ( functionResult . argumentErrors ) { argumentErrors = true ; } else { specializedInitSelfType = functionResult . specializedInitSelfType ; const transformed = applyFunctionTransform ( evaluatorInterface , errorNode , argList , expandedSubtype , { argumentErrors : functionResult . argumentErrors , returnType : functionResult . returnType ?? UnknownType . create ( ) , isTypeIncomplete , } ) ; functionResult . returnType = transformed . returnType ; if ( transformed . isTypeIncomplete ) { isTypeIncomplete = true ; } if ( transformed . argumentErrors ) { argumentErrors = true ; } } if ( ! functionResult . argumentErrors && expandedSubtype . details . builtInName === 'NewType' ) { return createNewType ( errorNode , argList ) ; } if ( expandedSubtype . details . builtInName === '__import__' ) { return AnyType . create ( ) ; } return functionResult . returnType ; } case TypeCategory . OverloadedFunction : { if ( expandedSubtype . overloads [ 0 ] . details . builtInName === 'cast' && argList . length === 2 ) { const castToType = getTypeForArgumentExpectingType ( argList [ 0 ] ) . type ; const castFromType = getTypeForArgument ( argList [ 1 ] ) . type ; if ( isInstantiableClass ( castToType ) && isClassInstance ( castFromType ) ) { if ( isTypeSame ( castToType , ClassType . cloneAsInstantiable ( castFromType ) , true ) ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportUnnecessaryCast , DiagnosticRule . reportUnnecessaryCast , Localizer . Diagnostic . unnecessaryCast ( ) . format ( { type : printType ( castFromType ) , } ) , errorNode ) ; } } return convertToInstance ( castToType ) ; } const functionResult = validateOverloadedFunctionArguments ( errorNode , argList , expandedSubtype , typeVarMap , skipUnknownArgCheck , expectedType ) ; if ( functionResult . isTypeIncomplete ) { isTypeIncomplete = true ; } if ( functionResult . argumentErrors ) { argumentErrors = true ; } else { specializedInitSelfType = functionResult . specializedInitSelfType ; const transformed = applyFunctionTransform ( evaluatorInterface , errorNode , argList , expandedSubtype , { argumentErrors : functionResult . argumentErrors , returnType : functionResult . returnType ?? UnknownType . create ( ) , isTypeIncomplete , } ) ; functionResult . returnType = transformed . returnType ; if ( transformed . isTypeIncomplete ) { isTypeIncomplete = true ; } if ( transformed . argumentErrors ) { argumentErrors = true ; } } return functionResult . returnType || UnknownType . create ( ) ; } case TypeCategory . Class : { if ( TypeBase . isInstantiable ( expandedSubtype ) ) { if ( expandedSubtype . literalValue !== undefined ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . literalNotCallable ( ) , errorNode ) ; argumentErrors = true ; return UnknownType . create ( ) ; } if ( ClassType . isBuiltIn ( expandedSubtype ) ) { const className = expandedSubtype . aliasName || expandedSubtype . details . name ; if ( className === 'type' ) { validateConstructorArguments ( errorNode , argList , expandedSubtype , skipUnknownArgCheck , expectedType ) ; if ( argList . length === 1 ) { const argType = getTypeForArgument ( argList [ 0 ] ) . type ; if ( isClassInstance ( argType ) || ( isTypeVar ( argType ) && TypeBase . isInstance ( argType ) ) || isNoneInstance ( argType ) ) { return convertToInstantiable ( stripLiteralValue ( argType ) ) ; } } else if ( argList . length >= 2 ) { return createType ( errorNode , argList ) || AnyType . create ( ) ; } return AnyType . create ( ) ; } if ( className === 'TypeVar' ) { return createTypeVarType ( errorNode , argList ) ; } if ( className === 'TypeVarTuple' ) { return createTypeVarTupleType ( errorNode , argList ) ; } if ( className === 'ParamSpec' ) { return createParamSpecType ( errorNode , argList ) ; } if ( className === 'NamedTuple' ) { return createNamedTupleType ( evaluatorInterface , errorNode , argList , true ) ; } if ( className === 'NewType' ) { return createNewType ( errorNode , argList ) ; } if ( className === 'Protocol' || className === 'Generic' || className === 'Callable' || className === 'Concatenate' || className === 'Type' ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( errorNode ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeNotIntantiable ( ) . format ( { type : className } ) , errorNode ) ; return AnyType . create ( ) ; } if ( className === 'Enum' || className === 'IntEnum' || className === 'StrEnum' || className === 'Flag' || className === 'IntFlag' ) { return createEnumType ( errorNode , expandedSubtype , argList ) ; } if ( className === 'TypedDict' ) { return createTypedDictType ( evaluatorInterface , errorNode , expandedSubtype , argList ) ; } if ( className === 'auto' && argList . length === 0 ) { return getBuiltInObject ( errorNode , 'int' ) ; } } if ( ClassType . supportsAbstractMethods ( expandedSubtype ) ) { const abstractMethods = getAbstractMethods ( expandedSubtype ) ; if ( abstractMethods . length > 0 && ! expandedSubtype . includeSubclasses && ! isTypeVar ( unexpandedSubtype ) ) { const diagAddendum = new DiagnosticAddendum ( ) ; const errorsToDisplay = 2 ; abstractMethods . forEach ( ( abstractMethod , index ) => { if ( index === errorsToDisplay ) { diagAddendum . addMessage ( Localizer . DiagnosticAddendum . memberIsAbstractMore ( ) . format ( { count : abstractMethods . length - errorsToDisplay , } ) ) ; } else if ( index < errorsToDisplay ) { if ( isInstantiableClass ( abstractMethod . classType ) ) { const className = abstractMethod . classType . details . name ; diagAddendum . addMessage ( Localizer . DiagnosticAddendum . memberIsAbstract ( ) . format ( { type : className , name : abstractMethod . symbolName , } ) ) ; } } } ) ; addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . instantiateAbstract ( ) . format ( { type : expandedSubtype . details . name , } ) + diagAddendum . getString ( ) , errorNode ) ; } } if ( ClassType . isProtocolClass ( expandedSubtype ) && ! expandedSubtype . includeSubclasses ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . instantiateProtocol ( ) . format ( { type : expandedSubtype . details . name , } ) , errorNode ) ; } const constructorResult = validateConstructorArguments ( errorNode , argList , expandedSubtype , skipUnknownArgCheck , expectedType ) ; if ( constructorResult . argumentErrors ) { argumentErrors = true ; } if ( constructorResult . isTypeIncomplete ) { isTypeIncomplete = true ; } let returnType = constructorResult . returnType ; if ( isTypeVar ( unexpandedSubtype ) ) { returnType = convertToInstance ( unexpandedSubtype ) ; } if ( returnType && isClassInstance ( returnType ) && returnType . details . mro . some ( ( baseClass ) => isInstantiableClass ( baseClass ) && ClassType . isBuiltIn ( baseClass , 'type' ) ) ) { const newClassName = '__class_' + returnType . details . name ; const newClassType = ClassType . createInstantiable ( newClassName , '' , '' , AnalyzerNodeInfo . getFileInfo ( errorNode ) . filePath , ClassTypeFlags . None , ParseTreeUtils . getTypeSourceId ( errorNode ) , ClassType . cloneAsInstantiable ( returnType ) , ClassType . cloneAsInstantiable ( returnType ) ) ; newClassType . details . baseClasses . push ( getBuiltInType ( errorNode , 'object' ) ) ; computeMroLinearization ( newClassType ) ; return newClassType ; } return returnType ; } else { let memberType = getTypeFromObjectMember ( errorNode , expandedSubtype , '__call__' ) ?. type ; if ( memberType && ( isFunction ( memberType ) || isOverloadedFunction ( memberType ) ) ) { memberType = removeParamSpecVariadicsFromSignature ( memberType ) ; const functionResult = validateCallArguments ( errorNode , argList , memberType , typeVarMap , skipUnknownArgCheck , expectedType , recursionCount + 1 ) ; if ( functionResult . argumentErrors ) { argumentErrors = true ; } return functionResult . returnType || UnknownType . create ( ) ; } if ( ! memberType || ! isAnyOrUnknown ( memberType ) ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . objectNotCallable ( ) . format ( { type : printType ( expandedSubtype ) , } ) , errorNode ) ; } return UnknownType . create ( ) ; } } case TypeCategory . None : { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportOptionalCall , DiagnosticRule . reportOptionalCall , Localizer . Diagnostic . noneNotCallable ( ) , errorNode ) ; return undefined ; } case TypeCategory . TypeVar : { expandedSubtype = transformPossibleRecursiveTypeAlias ( expandedSubtype ) ; const callResult = validateCallArguments ( errorNode , argList , expandedSubtype , typeVarMap , skipUnknownArgCheck , expectedType , recursionCount + 1 ) ; if ( callResult . argumentErrors ) { argumentErrors = true ; } return callResult . returnType || UnknownType . create ( ) ; } case TypeCategory . Module : { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . moduleNotCallable ( ) , errorNode ) ; return undefined ; } } return undefined ; } ) ; return { argumentErrors , returnType : isNever ( returnType ) ? undefined : returnType , isTypeIncomplete , specializedInitSelfType , } ; } function matchFunctionArgumentsToParameters ( errorNode , argList , type , overloadIndex ) { let argIndex = 0 ; const typeParams = type . details . parameters ; let matchedUnpackedListOfUnknownLength = false ; const varArgDictParam = typeParams . find ( ( param ) => param . category === ParameterCategory . VarArgDictionary ) ; let reportedArgError = false ; let isTypeIncomplete = false ; let positionalOnlyIndex = typeParams . findIndex ( ( param ) => param . category === ParameterCategory . Simple && ! param . name ) ; const paramMap = new Map < string , ParamAssignmentInfo > ( ) ; typeParams . forEach ( ( param , index ) => { if ( param . name && param . category === ParameterCategory . Simple ) { paramMap . set ( param . name , { argsNeeded : param . category === ParameterCategory . Simple && ! param . hasDefault ? 1 : 0 , argsReceived : 0 , isPositionalOnly : positionalOnlyIndex >= 0 && index < positionalOnlyIndex , } ) ; } } ) ; let positionParamLimitIndex = typeParams . findIndex ( ( param ) => param . category === ParameterCategory . VarArgList && ! param . name ) ; const varArgListParamIndex = typeParams . findIndex ( ( param ) => param . category === ParameterCategory . VarArgList ) ; const varArgDictParamIndex = typeParams . findIndex ( ( param ) => param . category === ParameterCategory . VarArgDictionary ) ; if ( positionParamLimitIndex < 0 ) { positionParamLimitIndex = varArgListParamIndex ; if ( positionParamLimitIndex >= 0 ) { positionParamLimitIndex ++ ; } } if ( positionParamLimitIndex < 0 ) { positionParamLimitIndex = varArgDictParamIndex ; } let paramSpecArgList ; let paramSpecTarget ; let hasParamSpecArgsKwargs = false ; if ( varArgListParamIndex >= 0 && varArgDictParamIndex >= 0 ) { const varArgListParam = typeParams [ varArgListParamIndex ] ; const varArgDictParam = typeParams [ varArgDictParamIndex ] ; if ( isParamSpec ( varArgListParam . type ) && varArgListParam . type . paramSpecAccess === 'args' && isParamSpec ( varArgDictParam . type ) && varArgDictParam . type . paramSpecAccess === 'kwargs' && varArgListParam . type . details . name === varArgDictParam . type . details . name ) { hasParamSpecArgsKwargs = true ; if ( varArgListParam . type . scopeId === type . details . typeVarScopeId ) { paramSpecArgList = [ ] ; paramSpecTarget = TypeVarType . cloneForParamSpecAccess ( varArgListParam . type , undefined ) ; } else { positionalOnlyIndex = varArgListParamIndex ; } } } argList . forEach ( ( arg ) => { if ( arg . name ) { const namedParamIndex = typeParams . findIndex ( ( param ) => param . name === arg . name ! . value && param . category === ParameterCategory . Simple ) ; if ( namedParamIndex >= 0 && namedParamIndex > positionalOnlyIndex ) { if ( positionParamLimitIndex < 0 || namedParamIndex < positionParamLimitIndex ) { positionParamLimitIndex = namedParamIndex ; } } } } ) ; if ( positionParamLimitIndex < 0 ) { positionParamLimitIndex = typeParams . length ; } let positionalArgCount = argList . findIndex ( ( arg ) => arg . argumentCategory === ArgumentCategory . UnpackedDictionary || arg . name !== undefined ) ; if ( positionalArgCount < 0 ) { positionalArgCount = argList . length ; } let validateArgTypeParams = [ ] ; let activeParam ; function trySetActive ( arg , param ) { if ( arg . active ) { activeParam = param ; } } let foundUnpackedListArg = argList . find ( ( arg ) => arg . argumentCategory === ArgumentCategory . UnpackedList ) !== undefined ; let paramIndex = 0 ; let unpackedArgIndex = 0 ; let unpackedParamIndex = 0 ; while ( argIndex < positionalArgCount ) { if ( paramIndex === positionalOnlyIndex ) { paramIndex ++ ; continue ; } if ( argIndex < positionalOnlyIndex && argList [ argIndex ] . name ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( argList [ argIndex ] . name ! ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . argPositional ( ) , argList [ argIndex ] . name ! ) ; reportedArgError = true ; } if ( paramIndex >= positionParamLimitIndex ) { if ( ! foundUnpackedListArg || argList [ argIndex ] . argumentCategory !== ArgumentCategory . UnpackedList ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , positionParamLimitIndex === 1 ? Localizer . Diagnostic . argPositionalExpectedOne ( ) : Localizer . Diagnostic . argPositionalExpectedCount ( ) . format ( { expected : positionParamLimitIndex , } ) , argList [ argIndex ] . valueExpression || errorNode ) ; reportedArgError = true ; } break ; } const paramType = FunctionType . getEffectiveParameterType ( type , paramIndex ) ; if ( argList [ argIndex ] . argumentCategory === ArgumentCategory . UnpackedList ) { if ( ! argList [ argIndex ] . valueExpression ) { break ; } const isParamVariadic = typeParams [ paramIndex ] . category === ParameterCategory . VarArgList && isVariadicTypeVar ( paramType ) ; let isArgCompatibleWithVariadic = false ; const argTypeResult = getTypeForArgument ( argList [ argIndex ] ) ; const argType = argTypeResult . type ; let listElementType ; let advanceToNextArg = false ; if ( type . details . paramSpec && paramIndex < positionParamLimitIndex ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , positionParamLimitIndex === 1 ? Localizer . Diagnostic . argPositionalExpectedOne ( ) : Localizer . Diagnostic . argPositionalExpectedCount ( ) . format ( { expected : positionParamLimitIndex , } ) , argList [ argIndex ] . valueExpression || errorNode ) ; reportedArgError = true ; } const combinedTupleType = combineSameSizedTuples ( makeTopLevelTypeVarsConcrete ( argType ) , tupleClassType ) ; if ( ! isParamVariadic && combinedTupleType && isClassInstance ( combinedTupleType ) && combinedTupleType . tupleTypeArguments && combinedTupleType . tupleTypeArguments . length > 0 ) { listElementType = combinedTupleType . tupleTypeArguments [ unpackedArgIndex ] ; foundUnpackedListArg = argList . find ( ( arg , index ) => index > argIndex && arg . argumentCategory === ArgumentCategory . UnpackedList ) !== undefined ; unpackedArgIndex ++ ; if ( unpackedArgIndex >= combinedTupleType . tupleTypeArguments . length ) { unpackedArgIndex = 0 ; advanceToNextArg = true ; } } else if ( isParamVariadic && isVariadicTypeVar ( argType ) ) { listElementType = argType ; isArgCompatibleWithVariadic = true ; } else if ( isParamSpec ( argType ) && argType . paramSpecAccess === 'args' ) { listElementType = undefined ; } else { listElementType = getTypeFromIterator ( argType , false , argList [ argIndex ] . valueExpression ! ) || UnknownType . create ( ) ; if ( typeParams [ paramIndex ] . category !== ParameterCategory . VarArgList ) { matchedUnpackedListOfUnknownLength = true ; } } const funcArg = listElementType ? { argumentCategory : ArgumentCategory . Simple , type : listElementType , } : undefined ; if ( funcArg && argTypeResult . isIncomplete ) { isTypeIncomplete = true ; } const paramName = typeParams [ paramIndex ] . name ; if ( isParamVariadic && ! isArgCompatibleWithVariadic ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . unpackedArgWithVariadicParam ( ) , argList [ argIndex ] . valueExpression || errorNode ) ; reportedArgError = true ; } else { if ( paramSpecArgList ) { paramSpecArgList . push ( argList [ argIndex ] ) ; } if ( funcArg ) { validateArgTypeParams . push ( { paramCategory : typeParams [ paramIndex ] . category , paramType , requiresTypeVarMatching : requiresSpecialization ( paramType ) , argument : funcArg , errorNode : argList [ argIndex ] . valueExpression || errorNode , paramName : typeParams [ paramIndex ] . isNameSynthesized ? undefined : paramName , } ) ; } } trySetActive ( argList [ argIndex ] , typeParams [ paramIndex ] ) ; if ( paramName && typeParams [ paramIndex ] . category === ParameterCategory . Simple && paramMap . has ( paramName ) ) { paramMap . get ( paramName ) ! . argsReceived ++ ; } if ( advanceToNextArg || typeParams [ paramIndex ] . category === ParameterCategory . VarArgList ) { argIndex ++ ; } if ( typeParams [ paramIndex ] . category !== ParameterCategory . VarArgList ) { paramIndex ++ ; } } else if ( typeParams [ paramIndex ] . category === ParameterCategory . VarArgList ) { trySetActive ( argList [ argIndex ] , typeParams [ paramIndex ] ) ; if ( paramSpecArgList ) { paramSpecArgList . push ( argList [ argIndex ] ) ; } else { let paramCategory = typeParams [ paramIndex ] . category ; let effectiveParamType = paramType ; const paramName = typeParams [ paramIndex ] . name ; if ( isVariadicTypeVar ( typeParams [ paramIndex ] . type ) && isClassInstance ( paramType ) && isTupleClass ( paramType ) && paramType . tupleTypeArguments && unpackedParamIndex < paramType . tupleTypeArguments . length ) { effectiveParamType = paramType . tupleTypeArguments [ unpackedParamIndex ] ; paramCategory = isVariadicTypeVar ( effectiveParamType ) ? ParameterCategory . VarArgList : ParameterCategory . Simple ; unpackedParamIndex ++ ; const paramsToFillCount = positionalArgCount - argIndex - 1 ; const argsRemainingCount = paramType . tupleTypeArguments . length - unpackedParamIndex ; if ( unpackedParamIndex >= paramType . tupleTypeArguments . length ) { paramIndex ++ ; } else if ( argsRemainingCount > 0 && paramsToFillCount <= 0 ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , argsRemainingCount === 1 ? Localizer . Diagnostic . argMorePositionalExpectedOne ( ) : Localizer . Diagnostic . argMorePositionalExpectedCount ( ) . format ( { expected : argsRemainingCount , } ) , argList [ argIndex ] . valueExpression || errorNode ) ; reportedArgError = true ; } } validateArgTypeParams . push ( { paramCategory , paramType : effectiveParamType , requiresTypeVarMatching : requiresSpecialization ( paramType ) , argument : argList [ argIndex ] , errorNode : argList [ argIndex ] . valueExpression || errorNode , paramName , mapsToVarArgList : true , } ) ; } argIndex ++ ; } else { const paramName = typeParams [ paramIndex ] . name ; validateArgTypeParams . push ( { paramCategory : typeParams [ paramIndex ] . category , paramType , requiresTypeVarMatching : requiresSpecialization ( paramType ) , argument : argList [ argIndex ] , errorNode : argList [ argIndex ] . valueExpression || errorNode , paramName : typeParams [ paramIndex ] . isNameSynthesized ? undefined : paramName , } ) ; trySetActive ( argList [ argIndex ] , typeParams [ paramIndex ] ) ; if ( paramName && paramMap . has ( paramName ) ) { paramMap . get ( paramName ) ! . argsReceived ++ ; } argIndex ++ ; paramIndex ++ ; } } if ( positionalOnlyIndex >= 0 && paramIndex < positionalOnlyIndex && ( ! foundUnpackedListArg || hasParamSpecArgsKwargs ) ) { const firstParamWithDefault = typeParams . findIndex ( ( param ) => param . hasDefault ) ; const positionOnlyWithoutDefaultsCount = firstParamWithDefault >= 0 && firstParamWithDefault < positionalOnlyIndex ? firstParamWithDefault : positionalOnlyIndex ; const argsRemainingCount = positionOnlyWithoutDefaultsCount - positionalArgCount ; if ( argsRemainingCount > 0 ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , argsRemainingCount === 1 ? Localizer . Diagnostic . argMorePositionalExpectedOne ( ) : Localizer . Diagnostic . argMorePositionalExpectedCount ( ) . format ( { expected : argsRemainingCount , } ) , argList . length > positionalArgCount ? argList [ positionalArgCount ] . valueExpression || errorNode : errorNode ) ; reportedArgError = true ; } } if ( ! reportedArgError ) { let unpackedDictionaryArgType ; while ( argIndex < argList . length ) { if ( argList [ argIndex ] . argumentCategory === ArgumentCategory . UnpackedDictionary ) { const argType = getTypeForArgument ( argList [ argIndex ] ) . type ; if ( isAnyOrUnknown ( argType ) ) { unpackedDictionaryArgType = argType ; } else if ( isClassInstance ( argType ) && ClassType . isTypedDictClass ( argType ) ) { const typedDictEntries = getTypedDictMembersForClass ( evaluatorInterface , argType ) ; const diag = new DiagnosticAddendum ( ) ; typedDictEntries . forEach ( ( entry , name ) => { const paramEntry = paramMap . get ( name ) ; if ( paramEntry && ! paramEntry . isPositionalOnly ) { if ( paramEntry . argsReceived > 0 ) { diag . addMessage ( Localizer . Diagnostic . paramAlreadyAssigned ( ) . format ( { name } ) ) ; } else { paramEntry . argsReceived ++ ; const paramInfoIndex = typeParams . findIndex ( ( param ) => param . name === name ) ; assert ( paramInfoIndex >= 0 ) ; const paramType = FunctionType . getEffectiveParameterType ( type , paramInfoIndex ) ; validateArgTypeParams . push ( { paramCategory : ParameterCategory . Simple , paramType , requiresTypeVarMatching : requiresSpecialization ( paramType ) , argument : { argumentCategory : ArgumentCategory . Simple , type : entry . valueType , } , errorNode : argList [ argIndex ] . valueExpression || errorNode , paramName : name , } ) ; } } else if ( varArgDictParam ) { assert ( varArgDictParamIndex >= 0 ) ; const paramType = FunctionType . getEffectiveParameterType ( type , varArgDictParamIndex ) ; validateArgTypeParams . push ( { paramCategory : ParameterCategory . VarArgDictionary , paramType , requiresTypeVarMatching : requiresSpecialization ( varArgDictParam . type ) , argument : { argumentCategory : ArgumentCategory . Simple , type : entry . valueType , } , errorNode : argList [ argIndex ] . valueExpression || errorNode , paramName : name , } ) ; paramMap . set ( name , { argsNeeded : 1 , argsReceived : 1 , isPositionalOnly : false , } ) ; } else { diag . addMessage ( Localizer . Diagnostic . paramNameMissing ( ) . format ( { name } ) ) ; } } ) ; if ( ! diag . isEmpty ( ) ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . unpackedTypedDictArgument ( ) + diag . getString ( ) , argList [ argIndex ] . valueExpression || errorNode ) ; reportedArgError = true ; } } else if ( isParamSpec ( argType ) && argType . paramSpecAccess === 'kwargs' ) { unpackedDictionaryArgType = AnyType . create ( ) ; } else { const mappingType = getTypingType ( errorNode , 'Mapping' ) ; const strObjType = getBuiltInObject ( errorNode , 'str' ) ; if ( mappingType && isInstantiableClass ( mappingType ) && strObjType && isClassInstance ( strObjType ) ) { const mappingTypeVarMap = new TypeVarMap ( getTypeVarScopeId ( mappingType ) ) ; let isValidMappingType = false ; if ( isTypeVar ( argType ) ) { isValidMappingType = true ; } else if ( canAssignType ( ClassType . cloneAsInstance ( mappingType ) , argType , undefined , mappingTypeVarMap ) ) { const specializedMapping = applySolvedTypeVars ( mappingType , mappingTypeVarMap ) as ClassType ; const typeArgs = specializedMapping . typeArguments ; if ( typeArgs && typeArgs . length >= 2 ) { if ( canAssignType ( strObjType , typeArgs [ 0 ] ) ) { isValidMappingType = true ; } unpackedDictionaryArgType = typeArgs [ 1 ] ; } else { isValidMappingType = true ; unpackedDictionaryArgType = UnknownType . create ( ) ; } } if ( ! isValidMappingType ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . unpackedDictArgumentNotMapping ( ) , argList [ argIndex ] . valueExpression || errorNode ) ; reportedArgError = true ; } } } if ( paramSpecArgList ) { paramSpecArgList . push ( argList [ argIndex ] ) ; } } else { const paramName = argList [ argIndex ] . name ; if ( paramName ) { const paramNameValue = paramName . value ; const paramEntry = paramMap . get ( paramNameValue ) ; if ( paramEntry && ! paramEntry . isPositionalOnly ) { if ( paramEntry . argsReceived > 0 ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( paramName ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . paramAlreadyAssigned ( ) . format ( { name : paramNameValue } ) , paramName ) ; reportedArgError = true ; } else { paramEntry . argsReceived ++ ; const paramInfoIndex = typeParams . findIndex ( ( param ) => param . name === paramNameValue ) ; assert ( paramInfoIndex >= 0 ) ; const paramType = FunctionType . getEffectiveParameterType ( type , paramInfoIndex ) ; validateArgTypeParams . push ( { paramCategory : ParameterCategory . Simple , paramType , requiresTypeVarMatching : requiresSpecialization ( paramType ) , argument : argList [ argIndex ] , errorNode : argList [ argIndex ] . valueExpression || errorNode , paramName : paramNameValue , } ) ; trySetActive ( argList [ argIndex ] , typeParams [ paramInfoIndex ] ) ; } } else if ( varArgDictParam ) { assert ( varArgDictParamIndex >= 0 ) ; if ( paramSpecArgList ) { paramSpecArgList . push ( argList [ argIndex ] ) ; } else { const paramType = FunctionType . getEffectiveParameterType ( type , varArgDictParamIndex ) ; validateArgTypeParams . push ( { paramCategory : ParameterCategory . VarArgDictionary , paramType , requiresTypeVarMatching : requiresSpecialization ( varArgDictParam . type ) , argument : argList [ argIndex ] , errorNode : argList [ argIndex ] . valueExpression || errorNode , paramName : paramNameValue , } ) ; paramMap . set ( paramNameValue , { argsNeeded : 1 , argsReceived : 1 , isPositionalOnly : false , } ) ; } trySetActive ( argList [ argIndex ] , varArgDictParam ) ; } else { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( paramName ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . paramNameMissing ( ) . format ( { name : paramName . value } ) , paramName ) ; reportedArgError = true ; } } else if ( argList [ argIndex ] . argumentCategory === ArgumentCategory . Simple ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( errorNode ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , positionParamLimitIndex === 1 ? Localizer . Diagnostic . argPositionalExpectedOne ( ) : Localizer . Diagnostic . argPositionalExpectedCount ( ) . format ( { expected : positionParamLimitIndex , } ) , argList [ argIndex ] . valueExpression || errorNode ) ; reportedArgError = true ; } } argIndex ++ ; } if ( unpackedDictionaryArgType && ( ! foundUnpackedListArg || varArgListParamIndex >= 0 ) ) { const firstKeywordArgIndex = foundUnpackedListArg ? varArgListParamIndex + 1 : positionalOnlyIndex >= 0 ? positionalOnlyIndex + 1 : 0 ; typeParams . forEach ( ( param , paramIndex ) => { if ( paramIndex >= firstKeywordArgIndex && param . category === ParameterCategory . Simple && param . name && ! param . hasDefault && paramMap . has ( param . name ) && paramMap . get ( param . name ) ! . argsReceived === 0 ) { const paramType = FunctionType . getEffectiveParameterType ( type , paramIndex ) ; validateArgTypeParams . push ( { paramCategory : ParameterCategory . Simple , paramType , requiresTypeVarMatching : requiresSpecialization ( paramType ) , argument : { argumentCategory : ArgumentCategory . Simple , type : unpackedDictionaryArgType ! , } , errorNode : errorNode , paramName : param . isNameSynthesized ? undefined : param . name , } ) ; paramMap . get ( param . name ) ! . argsReceived = 1 ; } } ) ; } if ( ! unpackedDictionaryArgType && ! FunctionType . isDefaultParameterCheckDisabled ( type ) ) { const unassignedParams = [ ... paramMap . keys ( ) ] . filter ( ( name ) => { const entry = paramMap . get ( name ) ! ; return ! entry || entry . argsReceived < entry . argsNeeded ; } ) ; if ( unassignedParams . length > 0 ) { const missingParamNames = unassignedParams . map ( ( p ) => `"${ p }"` ) . join ( ', ' ) ; addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , unassignedParams . length === 1 ? Localizer . Diagnostic . argMissingForParam ( ) . format ( { name : missingParamNames } ) : Localizer . Diagnostic . argMissingForParams ( ) . format ( { names : missingParamNames } ) , errorNode ) ; reportedArgError = true ; } typeParams . forEach ( ( param , index ) => { if ( param . category === ParameterCategory . Simple && param . name ) { const entry = paramMap . get ( param . name ) ! ; if ( entry . argsNeeded === 0 && entry . argsReceived === 0 ) { if ( param . defaultType && ! isEllipsisType ( param . defaultType ) && requiresSpecialization ( param . type ) ) { validateArgTypeParams . push ( { paramCategory : param . category , paramType : param . type , requiresTypeVarMatching : true , argument : { argumentCategory : ArgumentCategory . Simple , type : param . defaultType , } , errorNode : errorNode , paramName : param . isNameSynthesized ? undefined : param . name , } ) ; } } } } ) ; } } if ( ! reportedArgError || ! speculativeTypeTracker . isSpeculative ( undefined ) ) { if ( varArgListParamIndex >= 0 && typeParams [ varArgListParamIndex ] . hasDeclaredType ) { const paramType = FunctionType . getEffectiveParameterType ( type , varArgListParamIndex ) ; const variadicArgs = validateArgTypeParams . filter ( ( argParam ) => argParam . mapsToVarArgList ) ; if ( isTypeVar ( paramType ) && paramType . details . isVariadic ) { if ( tupleClassType && isInstantiableClass ( tupleClassType ) ) { const tupleTypeArgs = variadicArgs . map ( ( argParam ) => stripLiteralValue ( getTypeForArgument ( argParam . argument ) . type ) ) ; const specializedTuple = ClassType . cloneAsInstance ( specializeTupleClass ( tupleClassType , tupleTypeArgs , true , true , true ) ) ; const combinedArg = { paramCategory : ParameterCategory . VarArgList , paramType , requiresTypeVarMatching : true , argument : { argumentCategory : ArgumentCategory . Simple , type : specializedTuple } , errorNode , paramName : typeParams [ varArgListParamIndex ] . name , mapsToVarArgList : true , } ; validateArgTypeParams = [ ... validateArgTypeParams . filter ( ( argParam ) => ! argParam . mapsToVarArgList ) , combinedArg , ] ; } } } } let relevance = 0 ; if ( matchedUnpackedListOfUnknownLength ) { relevance -- ; } if ( [ 'isinstance' , 'issubclass' ] . some ( ( name ) => name === type . details . builtInName ) && validateArgTypeParams . length === 2 ) { validateArgTypeParams [ 1 ] . expectingType = true ; } return { overload : type , overloadIndex , argumentErrors : reportedArgError , isTypeIncomplete , argParams : validateArgTypeParams , paramSpecTarget , paramSpecArgList , activeParam , relevance , } ; } function validateFunctionArgumentTypes ( errorNode , matchResults , typeVarMap , skipUnknownArgCheck = false , expectedType ? ) { let isTypeIncomplete = matchResults . isTypeIncomplete ; let argumentErrors = false ; let specializedInitSelfType ; const type = matchResults . overload ; const typeCondition = getTypeCondition ( type ) ; if ( type . boundTypeVarScopeId ) { if ( type . preBoundFlags !== undefined && type . boundToType && requiresSpecialization ( type . boundToType ) ) { if ( type . preBoundFlags & ( FunctionTypeFlags . StaticMethod | FunctionTypeFlags . ClassMethod | FunctionTypeFlags . StaticMethod ) ) { typeVarMap . addSolveForScope ( type . boundTypeVarScopeId ) ; } } if ( type . details . name === '__init__' && FunctionType . isOverloaded ( type ) && type . strippedFirstParamType && type . boundToType && isClassInstance ( type . strippedFirstParamType ) && isClassInstance ( type . boundToType ) && ClassType . isSameGenericClass ( type . strippedFirstParamType , type . boundToType ) && type . strippedFirstParamType . typeArguments ) { const typeParams = type . strippedFirstParamType . details . typeParameters ; specializedInitSelfType = type . strippedFirstParamType ; type . strippedFirstParamType . typeArguments . forEach ( ( typeArg , index ) => { if ( index < typeParams . length ) { const typeParam = typeParams [ index ] ; if ( ! isTypeSame ( typeParam , typeArg , true ) ) { typeVarMap . setTypeVarType ( typeParams [ index ] , typeArg ) ; } } } ) ; } } if ( expectedType && ! isAnyOrUnknown ( expectedType ) && ! requiresSpecialization ( expectedType ) && type . details . declaredReturnType ) { if ( ! isUnion ( expectedType ) || containsLiteralType ( expectedType , true ) ) { const effectiveReturnType = getFunctionEffectiveReturnType ( type ) ; let effectiveExpectedType = expectedType ; if ( isClassInstance ( effectiveReturnType ) && isClassInstance ( expectedType ) && ! ClassType . isSameGenericClass ( effectiveReturnType , expectedType ) ) { const tempTypeVarMap = new TypeVarMap ( getTypeVarScopeId ( effectiveReturnType ) ) ; populateTypeVarMapBasedOnExpectedType ( ClassType . cloneAsInstantiable ( effectiveReturnType ) , expectedType , tempTypeVarMap , getTypeVarScopesForNode ( errorNode ) ) ; const genericReturnType = ClassType . cloneForSpecialization ( effectiveReturnType , undefined , false ) ; effectiveExpectedType = applySolvedTypeVars ( genericReturnType , tempTypeVarMap ) ; } canAssignType ( effectiveReturnType , effectiveExpectedType , undefined , typeVarMap , CanAssignFlags . AllowTypeVarNarrowing | CanAssignFlags . RetainLiteralsForTypeVar ) ; } } if ( [ 'cast' , 'isinstance' , 'issubclass' ] . some ( ( name ) => name === type . details . builtInName ) ) { skipUnknownArgCheck = true ; } const typeVarMatchingCount = matchResults . argParams . filter ( ( arg ) => arg . requiresTypeVarMatching ) . length ; if ( typeVarMatchingCount > 0 ) { let passCount = Math . min ( typeVarMatchingCount , 2 ) ; for ( let i = 0 ; i < passCount ; i ++ ) { useSpeculativeMode ( errorNode , ( ) => { matchResults . argParams . forEach ( ( argParam ) => { if ( argParam . requiresTypeVarMatching ) { const argResult = validateArgType ( argParam , typeVarMap , type . details . name , skipUnknownArgCheck , i === 0 , typeCondition ) ; if ( argResult . isTypeIncomplete ) { isTypeIncomplete = true ; } if ( i === 0 && argResult . skippedOverloadArg ) { passCount ++ ; } } } ) ; } ) ; } typeVarMap . lock ( ) ; } matchResults . argParams . forEach ( ( argParam ) => { const argResult = validateArgType ( argParam , typeVarMap , type . details . name , skipUnknownArgCheck , false , typeCondition ) ; if ( ! argResult . isCompatible ) { argumentErrors = true ; } if ( argResult . isTypeIncomplete ) { isTypeIncomplete = true ; } } ) ; if ( matchResults . paramSpecArgList && matchResults . paramSpecTarget ) { if ( ! validateFunctionArgumentsForParamSpec ( errorNode , matchResults . paramSpecArgList , matchResults . paramSpecTarget , typeVarMap , typeCondition ) ) { argumentErrors = true ; } } const returnType = getFunctionEffectiveReturnType ( type , matchResults . argParams ) ; let eliminateUnsolvedInUnions = true ; let curNode = errorNode ; while ( true ) { const typeVarScopeNode = ParseTreeUtils . getTypeVarScopeNode ( curNode ) ; if ( ! typeVarScopeNode ) { break ; } const typeVarScopeId = getScopeIdForNode ( typeVarScopeNode ) ; if ( typeVarMap . hasSolveForScope ( typeVarScopeId ) ) { eliminateUnsolvedInUnions = false ; } curNode = typeVarScopeNode ; } if ( isFunction ( returnType ) || isOverloadedFunction ( returnType ) ) { eliminateUnsolvedInUnions = false ; } let specializedReturnType = addConditionToType ( applySolvedTypeVars ( returnType , typeVarMap , false , false , eliminateUnsolvedInUnions ) , typeCondition ) ; if ( isClassInstance ( specializedReturnType ) && ClassType . isBuiltIn ( specializedReturnType , 'TypeGuard' ) && specializedReturnType . typeArguments && specializedReturnType . typeArguments . length > 0 ) { if ( boolClassType && isInstantiableClass ( boolClassType ) ) { const positiveType = specializedReturnType . typeArguments [ 0 ] ; const negativeType = specializedReturnType . typeArguments . length > 1 ? specializedReturnType . typeArguments [ 1 ] : undefined ; specializedReturnType = ClassType . cloneAsInstance ( ClassType . cloneForTypeGuard ( boolClassType , positiveType , negativeType ) ) ; } } if ( isFunction ( specializedReturnType ) && ! specializedReturnType . details . name ) { specializedReturnType . details = { ... specializedReturnType . details , typeVarScopeId : WildcardTypeVarScopeId , } ; } if ( specializedInitSelfType ) { specializedInitSelfType = applySolvedTypeVars ( specializedInitSelfType , typeVarMap ) ; } return { argumentErrors , returnType : specializedReturnType , isTypeIncomplete , activeParam : matchResults . activeParam , specializedInitSelfType , } ; } function validateFunctionArguments ( errorNode , argList , type , typeVarMap , skipUnknownArgCheck = false , expectedType ? ) { const matchResults = matchFunctionArgumentsToParameters ( errorNode , argList , type , 0 ) ; if ( matchResults . argumentErrors ) { if ( ! incompleteTypeTracker . isUndoTrackingEnabled ( ) ) { argList . forEach ( ( arg ) => { if ( arg . valueExpression && ! speculativeTypeTracker . isSpeculative ( arg . valueExpression ) ) { getTypeOfExpression ( arg . valueExpression ) ; } } ) ; } return { argumentErrors : true , activeParam : matchResults . activeParam , } ; } return validateFunctionArgumentTypes ( errorNode , matchResults , typeVarMap , skipUnknownArgCheck , expectedType ) ; } function validateFunctionArgumentsForParamSpec ( errorNode , argList , paramSpec , typeVarMap , conditionFilter ) { const paramSpecValue = typeVarMap . getParamSpec ( paramSpec ) ; if ( ! paramSpecValue ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . paramSpecNotBound ( ) . format ( { type : printType ( paramSpec ) } ) , argList [ 0 ] ?. valueExpression || errorNode ) ; return false ; } let reportedArgError = false ; const paramMap = new Map < string , ParamSpecEntry > ( ) ; const paramSpecParams = paramSpecValue . parameters ; paramSpecParams . forEach ( ( param ) => { if ( param . name ) { paramMap . set ( param . name , param ) ; } } ) ; let positionalIndex = 0 ; argList . forEach ( ( arg ) => { if ( arg . argumentCategory === ArgumentCategory . Simple ) { let paramType ; if ( arg . name ) { const paramInfo = paramMap . get ( arg . name . value ) ; if ( paramInfo ) { paramType = paramInfo . type ; paramMap . delete ( arg . name . value ) ; } else { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . paramNameMissing ( ) . format ( { name : arg . name . value } ) , arg . valueExpression || errorNode ) ; reportedArgError = true ; } } else { if ( positionalIndex < paramSpecParams . length ) { const paramInfo = paramSpecParams [ positionalIndex ] ; paramType = paramInfo . type ; if ( paramInfo . name ) { paramMap . delete ( paramInfo . name ) ; } } else { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , paramSpecParams . length === 1 ? Localizer . Diagnostic . argPositionalExpectedOne ( ) : Localizer . Diagnostic . argPositionalExpectedCount ( ) . format ( { expected : paramSpecParams . length , } ) , arg . valueExpression || errorNode ) ; reportedArgError = true ; } positionalIndex ++ ; } if ( paramType ) { if ( ! validateArgType ( { paramCategory : ParameterCategory . Simple , paramType , requiresTypeVarMatching : false , argument : arg , errorNode : arg . valueExpression || errorNode , } , typeVarMap , '' , false , false , conditionFilter ) ) { reportedArgError = true ; } } } else { paramMap . clear ( ) ; } } ) ; if ( ! reportedArgError ) { let unassignedParams = [ ... paramMap . keys ( ) ] ; unassignedParams = unassignedParams . filter ( ( name ) => { const paramInfo = paramMap . get ( name ) ! ; return paramInfo . category === ParameterCategory . Simple && ! paramInfo . hasDefault ; } ) ; if ( unassignedParams . length > 0 && ! paramSpecValue . paramSpec ) { const missingParamNames = unassignedParams . map ( ( p ) => `"${ p }"` ) . join ( ', ' ) ; addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , unassignedParams . length === 1 ? Localizer . Diagnostic . argMissingForParam ( ) . format ( { name : missingParamNames } ) : Localizer . Diagnostic . argMissingForParams ( ) . format ( { names : missingParamNames } ) , errorNode ) ; reportedArgError = true ; } } return ! reportedArgError ; } function validateArgType ( argParam , typeVarMap , functionName , skipUnknownCheck , skipOverloadArg , conditionFilter ) { let argType ; let expectedTypeDiag ; let isTypeIncomplete = false ; let isCompatible = true ; if ( argParam . argument . valueExpression ) { let expectedType = isTypeVar ( argParam . paramType ) ? undefined : applySolvedTypeVars ( argParam . paramType , typeVarMap , false , true ) ; if ( expectedType && isUnknown ( expectedType ) ) { expectedType = undefined ; } if ( argParam . argType ) { argType = argParam . argType ; } else { const flags = argParam . expectingType ? EvaluatorFlags . EvaluateStringLiteralAsType | EvaluatorFlags . ParamSpecDisallowed | EvaluatorFlags . TypeVarTupleDisallowed : EvaluatorFlags . None ; const exprTypeResult = getTypeOfExpression ( argParam . argument . valueExpression , expectedType , flags ) ; argType = exprTypeResult . type ; if ( exprTypeResult . isIncomplete ) { isTypeIncomplete = true ; } if ( exprTypeResult . typeErrors ) { isCompatible = false ; } expectedTypeDiag = exprTypeResult . expectedTypeDiagAddendum ; } if ( argParam . argument && argParam . argument . name && ! speculativeTypeTracker . isSpeculative ( argParam . errorNode ) ) { writeTypeCache ( argParam . argument . name , expectedType || argType , EvaluatorFlags . None , isTypeIncomplete ) ; } } else { if ( argParam . argType ) { argType = argParam . argType ; } else if ( argParam . expectingType && ! argParam . argument . type && argParam . argument . valueExpression ) { const argTypeResult = getTypeOfExpression ( argParam . argument . valueExpression , undefined , EvaluatorFlags . EvaluateStringLiteralAsType | EvaluatorFlags . ParamSpecDisallowed | EvaluatorFlags . TypeVarTupleDisallowed ) ; argType = argTypeResult . type ; if ( argTypeResult . isIncomplete ) { isTypeIncomplete = true ; } } else { const argTypeResult = getTypeForArgument ( argParam . argument ) ; argType = argTypeResult . type ; if ( argTypeResult . isIncomplete ) { isTypeIncomplete = true ; } } } if ( argParam . paramCategory === ParameterCategory . VarArgDictionary && isTypeVar ( argParam . paramType ) ) { argType = stripLiteralValue ( argType ) ; } if ( conditionFilter ) { argType = mapSubtypesExpandTypeVars ( argType , conditionFilter , ( expandedSubtype ) => { return expandedSubtype ; } ) ; } let diag = new DiagnosticAddendum ( ) ; if ( isParamSpec ( argParam . paramType ) && argParam . paramType . paramSpecAccess !== undefined ) { return { isCompatible , isTypeIncomplete } ; } if ( skipOverloadArg ) { if ( isOverloadedFunction ( argType ) ) { return { isCompatible , isTypeIncomplete , skippedOverloadArg : true } ; } const concreteParamType = makeTopLevelTypeVarsConcrete ( argParam . paramType ) ; if ( isFunction ( concreteParamType ) || isOverloadedFunction ( concreteParamType ) ) { if ( isInstantiableClass ( argType ) ) { const constructor = createFunctionFromConstructor ( argType ) ; if ( constructor && isOverloadedFunction ( constructor ) ) { return { isCompatible , isTypeIncomplete , skippedOverloadArg : true } ; } } if ( isClassInstance ( argType ) ) { const callMember = lookUpObjectMember ( argType , '__call__' ) ; if ( callMember ) { const memberType = getTypeOfMember ( callMember ) ; if ( isOverloadedFunction ( memberType ) ) { return { isCompatible , isTypeIncomplete , skippedOverloadArg : true } ; } } } } } if ( ! canAssignType ( argParam . paramType , argType , diag . createAddendum ( ) , typeVarMap ) ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( argParam . errorNode ) ; if ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues !== 'none' && ! isDiagnosticSuppressedForNode ( argParam . errorNode ) ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( argParam . errorNode ) ; const argTypeText = printType ( argType ) ; const paramTypeText = printType ( argParam . paramType ) ; let message ; if ( argParam . paramName ) { if ( functionName ) { message = Localizer . Diagnostic . argAssignmentParamFunction ( ) . format ( { argType : argTypeText , paramType : paramTypeText , functionName , paramName : argParam . paramName , } ) ; } else { message = Localizer . Diagnostic . argAssignmentParam ( ) . format ( { argType : argTypeText , paramType : paramTypeText , paramName : argParam . paramName , } ) ; } } else { if ( functionName ) { message = Localizer . Diagnostic . argAssignmentFunction ( ) . format ( { argType : argTypeText , paramType : paramTypeText , functionName , } ) ; } else { message = Localizer . Diagnostic . argAssignment ( ) . format ( { argType : argTypeText , paramType : paramTypeText , } ) ; } } if ( expectedTypeDiag ) { diag = expectedTypeDiag ; } addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , message + diag . getString ( ) , argParam . errorNode ) ; } return { isCompatible : false , isTypeIncomplete } ; } if ( ! skipUnknownCheck ) { const simplifiedType = removeUnbound ( argType ) ; const fileInfo = AnalyzerNodeInfo . getFileInfo ( argParam . errorNode ) ; const getDiagAddendum = ( ) => { const diagAddendum = new DiagnosticAddendum ( ) ; if ( argParam . paramName ) { diagAddendum . addMessage ( ( functionName ? Localizer . DiagnosticAddendum . argParamFunction ( ) . format ( { paramName : argParam . paramName , functionName , } ) : Localizer . DiagnosticAddendum . argParam ( ) . format ( { paramName : argParam . paramName } ) ) + diagAddendum . getString ( ) ) ; } return diagAddendum ; } ; if ( fileInfo . diagnosticRuleSet . reportUnknownArgumentType !== 'none' && ! isAny ( argParam . paramType ) && ! isTypeIncomplete ) { if ( isUnknown ( simplifiedType ) ) { const diagAddendum = getDiagAddendum ( ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportUnknownArgumentType , DiagnosticRule . reportUnknownArgumentType , Localizer . Diagnostic . argTypeUnknown ( ) + diagAddendum . getString ( ) , argParam . errorNode ) ; } else if ( isPartlyUnknown ( simplifiedType , true ) ) { let suppressPartialUnknown = false ; if ( isInstantiableClass ( simplifiedType ) ) { suppressPartialUnknown = true ; } if ( isPartlyUnknown ( argParam . paramType ) ) { suppressPartialUnknown = true ; } if ( ! suppressPartialUnknown ) { const diagAddendum = getDiagAddendum ( ) ; diagAddendum . addMessage ( Localizer . DiagnosticAddendum . argumentType ( ) . format ( { type : printType ( simplifiedType , true ) , } ) ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportUnknownArgumentType , DiagnosticRule . reportUnknownArgumentType , Localizer . Diagnostic . argTypePartiallyUnknown ( ) + diagAddendum . getString ( ) , argParam . errorNode ) ; } } } } return { isCompatible , isTypeIncomplete } ; } function createTypeVarType ( errorNode , argList ) { let typeVarName = '' ; let firstConstraintArg ; if ( argList . length === 0 ) { addError ( Localizer . Diagnostic . typeVarFirstArg ( ) , errorNode ) ; return undefined ; } const firstArg = argList [ 0 ] ; if ( firstArg . valueExpression && firstArg . valueExpression . nodeType === ParseNodeType . StringList ) { typeVarName = firstArg . valueExpression . strings . map ( ( s ) => s . value ) . join ( '' ) ; } else { addError ( Localizer . Diagnostic . typeVarFirstArg ( ) , firstArg . valueExpression || errorNode ) ; } const typeVar = TypeVarType . createInstantiable ( typeVarName , false ) ; for ( let i = 1 ; i < argList . length ; i ++ ) { const paramNameNode = argList [ i ] . name ; const paramName = paramNameNode ? paramNameNode . value : undefined ; const paramNameMap = new Map < string , string > ( ) ; if ( paramName ) { if ( paramNameMap . get ( paramName ) ) { addError ( Localizer . Diagnostic . duplicateParam ( ) . format ( { name : paramName } ) , argList [ i ] . valueExpression || errorNode ) ; } if ( paramName === 'bound' ) { if ( typeVar . details . constraints . length > 0 ) { addError ( Localizer . Diagnostic . typeVarBoundAndConstrained ( ) , argList [ i ] . valueExpression || errorNode ) ; } else { const argType = getTypeForArgumentExpectingType ( argList [ i ] ) . type ; if ( requiresSpecialization ( argType , true ) ) { addError ( Localizer . Diagnostic . typeVarGeneric ( ) , argList [ i ] . valueExpression || errorNode ) ; } typeVar . details . boundType = convertToInstance ( argType ) ; } } else if ( paramName === 'covariant' ) { if ( argList [ i ] . valueExpression && getBooleanValue ( argList [ i ] . valueExpression ! ) ) { if ( typeVar . details . variance === Variance . Contravariant ) { addError ( Localizer . Diagnostic . typeVarVariance ( ) , argList [ i ] . valueExpression ! ) ; } else { typeVar . details . variance = Variance . Covariant ; } } } else if ( paramName === 'contravariant' ) { if ( argList [ i ] . valueExpression && getBooleanValue ( argList [ i ] . valueExpression ! ) ) { if ( typeVar . details . variance === Variance . Covariant ) { addError ( Localizer . Diagnostic . typeVarVariance ( ) , argList [ i ] . valueExpression ! ) ; } else { typeVar . details . variance = Variance . Contravariant ; } } } else { addError ( Localizer . Diagnostic . typeVarUnknownParam ( ) . format ( { name : paramName } ) , argList [ i ] . node ?. name || argList [ i ] . valueExpression || errorNode ) ; } paramNameMap . set ( paramName , paramName ) ; } else { if ( typeVar . details . boundType ) { addError ( Localizer . Diagnostic . typeVarBoundAndConstrained ( ) , argList [ i ] . valueExpression || errorNode ) ; } else { const argType = getTypeForArgumentExpectingType ( argList [ i ] ) . type ; if ( requiresSpecialization ( argType , true ) ) { addError ( Localizer . Diagnostic . typeVarGeneric ( ) , argList [ i ] . valueExpression || errorNode ) ; } TypeVarType . addConstraint ( typeVar , convertToInstance ( argType ) ) ; if ( firstConstraintArg === undefined ) { firstConstraintArg = argList [ i ] ; } } } } if ( typeVar . details . constraints . length === 1 && firstConstraintArg ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeVarSingleConstraint ( ) , firstConstraintArg . valueExpression || errorNode ) ; } return typeVar ; } function createTypeVarTupleType ( errorNode , argList ) { let typeVarName = '' ; if ( argList . length === 0 ) { addError ( Localizer . Diagnostic . typeVarFirstArg ( ) , errorNode ) ; return undefined ; } const firstArg = argList [ 0 ] ; if ( firstArg . valueExpression && firstArg . valueExpression . nodeType === ParseNodeType . StringList ) { typeVarName = firstArg . valueExpression . strings . map ( ( s ) => s . value ) . join ( '' ) ; } else { addError ( Localizer . Diagnostic . typeVarFirstArg ( ) , firstArg . valueExpression || errorNode ) ; } const typeVar = TypeVarType . createInstantiable ( typeVarName , false ) ; typeVar . details . isVariadic = true ; for ( let i = 1 ; i < argList . length ; i ++ ) { addError ( Localizer . Diagnostic . typeVarUnknownParam ( ) . format ( { name : argList [ i ] . name ?. value || '?' } ) , argList [ i ] . node ?. name || argList [ i ] . valueExpression || errorNode ) ; } return typeVar ; } function createParamSpecType ( errorNode , argList ) { if ( argList . length === 0 ) { addError ( Localizer . Diagnostic . paramSpecFirstArg ( ) , errorNode ) ; return undefined ; } const firstArg = argList [ 0 ] ; let paramSpecName = '' ; if ( firstArg . valueExpression && firstArg . valueExpression . nodeType === ParseNodeType . StringList ) { paramSpecName = firstArg . valueExpression . strings . map ( ( s ) => s . value ) . join ( '' ) ; } else { addError ( Localizer . Diagnostic . paramSpecFirstArg ( ) , firstArg . valueExpression || errorNode ) ; } const paramSpec = TypeVarType . createInstantiable ( paramSpecName , true ) ; for ( let i = 1 ; i < argList . length ; i ++ ) { if ( argList [ i ] . name ?. value ) { addError ( Localizer . Diagnostic . paramSpecUnknownParam ( ) . format ( { name : argList [ i ] . name ! . value } ) , argList [ i ] . node ?. name || argList [ i ] . valueExpression || errorNode ) ; } else { addError ( Localizer . Diagnostic . paramSpecUnknownArg ( ) , argList [ i ] . valueExpression || errorNode ) ; break ; } } return paramSpec ; } function getBooleanValue ( node ) { if ( node . nodeType === ParseNodeType . Constant ) { if ( node . constType === KeywordType . False ) { return false ; } else if ( node . constType === KeywordType . True ) { return true ; } } addError ( Localizer . Diagnostic . expectedBoolLiteral ( ) , node ) ; return false ; } function getFunctionFullName ( functionNode , moduleName , functionName ) { const nameParts = [ functionName ] ; let curNode = functionNode ; while ( curNode ) { curNode = ParseTreeUtils . getEnclosingClassOrFunction ( curNode ) ; if ( curNode ) { nameParts . push ( curNode . name . value ) ; } } nameParts . push ( moduleName ) ; return nameParts . reverse ( ) . join ( '.' ) ; } function createEnumType ( errorNode , enumClass , argList ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( errorNode ) ; let className = 'enum' ; if ( argList . length === 0 ) { return undefined ; } else { const nameArg = argList [ 0 ] ; if ( nameArg . argumentCategory === ArgumentCategory . Simple && nameArg . valueExpression && nameArg . valueExpression . nodeType === ParseNodeType . StringList ) { className = nameArg . valueExpression . strings . map ( ( s ) => s . value ) . join ( '' ) ; } else { return undefined ; } } const classType = ClassType . createInstantiable ( className , ParseTreeUtils . getClassFullName ( errorNode , fileInfo . moduleName , className ) , fileInfo . moduleName , fileInfo . filePath , ClassTypeFlags . EnumClass , ParseTreeUtils . getTypeSourceId ( errorNode ) , undefined , enumClass . details . effectiveMetaclass ) ; classType . details . baseClasses . push ( enumClass ) ; computeMroLinearization ( classType ) ; const classFields = classType . details . fields ; classFields . set ( '__class__' , Symbol . createWithType ( SymbolFlags . ClassMember | SymbolFlags . IgnoredForProtocolMatch , classType ) ) ; if ( argList . length < 2 ) { return undefined ; } else { const entriesArg = argList [ 1 ] ; if ( entriesArg . argumentCategory !== ArgumentCategory . Simple || ! entriesArg . valueExpression || entriesArg . valueExpression . nodeType !== ParseNodeType . StringList ) { return undefined ; } else { const entries = entriesArg . valueExpression . strings . map ( ( s ) => s . value ) . join ( '' ) . split ( ' ' ) ; entries . forEach ( ( entryName ) => { entryName = entryName . trim ( ) ; if ( entryName ) { const entryType = UnknownType . create ( ) ; const newSymbol = Symbol . createWithType ( SymbolFlags . ClassMember , entryType ) ; const stringNode = entriesArg . valueExpression ! ; assert ( stringNode . nodeType === ParseNodeType . StringList ) ; const fileInfo = AnalyzerNodeInfo . getFileInfo ( errorNode ) ; const declaration = { type : DeclarationType . Variable , node : stringNode as StringListNode , isRuntimeTypeExpression : true , path : fileInfo . filePath , range : convertOffsetsToRange ( stringNode . start , TextRange . getEnd ( stringNode ) , fileInfo . lines ) , moduleName : fileInfo . moduleName , } ; newSymbol . addDeclaration ( declaration ) ; classFields . set ( entryName , newSymbol ) ; } } ) ; } } return classType ; } function createNewType ( errorNode , argList ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( errorNode ) ; let className = '_' ; if ( argList . length >= 1 ) { const nameArg = argList [ 0 ] ; if ( nameArg . argumentCategory === ArgumentCategory . Simple ) { if ( nameArg . valueExpression && nameArg . valueExpression . nodeType === ParseNodeType . StringList ) { className = nameArg . valueExpression . strings . map ( ( s ) => s . value ) . join ( '' ) ; } } } if ( argList . length >= 2 ) { const baseClass = getTypeForArgumentExpectingType ( argList [ 1 ] ) . type ; if ( isInstantiableClass ( baseClass ) ) { if ( ClassType . isProtocolClass ( baseClass ) ) { addError ( Localizer . Diagnostic . newTypeProtocolClass ( ) , argList [ 1 ] . node || errorNode ) ; } else if ( baseClass . literalValue !== undefined ) { addError ( Localizer . Diagnostic . newTypeLiteral ( ) , argList [ 1 ] . node || errorNode ) ; } const classFlags = baseClass . details . flags & ~ ( ClassTypeFlags . BuiltInClass | ClassTypeFlags . SpecialBuiltIn ) ; const classType = ClassType . createInstantiable ( className , ParseTreeUtils . getClassFullName ( errorNode , fileInfo . moduleName , className ) , fileInfo . moduleName , fileInfo . filePath , classFlags , ParseTreeUtils . getTypeSourceId ( errorNode ) , undefined , baseClass . details . effectiveMetaclass ) ; classType . details . baseClasses . push ( baseClass ) ; computeMroLinearization ( classType ) ; const initType = FunctionType . createInstance ( '__init__' , '' , '' , FunctionTypeFlags . SynthesizedMethod ) ; FunctionType . addParameter ( initType , { category : ParameterCategory . Simple , name : 'self' , type : ClassType . cloneAsInstance ( classType ) , hasDeclaredType : true , } ) ; FunctionType . addParameter ( initType , { category : ParameterCategory . Simple , name : '_x' , type : ClassType . cloneAsInstance ( baseClass ) , hasDeclaredType : true , } ) ; initType . details . declaredReturnType = NoneType . createInstance ( ) ; classType . details . fields . set ( '__init__' , Symbol . createWithType ( SymbolFlags . ClassMember , initType ) ) ; const newType = FunctionType . createInstance ( '__new__' , '' , '' , FunctionTypeFlags . ConstructorMethod | FunctionTypeFlags . SynthesizedMethod ) ; FunctionType . addParameter ( newType , { category : ParameterCategory . Simple , name : 'cls' , type : classType , hasDeclaredType : true , } ) ; FunctionType . addDefaultParameters ( newType ) ; newType . details . declaredReturnType = ClassType . cloneAsInstance ( classType ) ; classType . details . fields . set ( '__new__' , Symbol . createWithType ( SymbolFlags . ClassMember , newType ) ) ; return classType ; } else if ( ! isAnyOrUnknown ( baseClass ) ) { addError ( Localizer . Diagnostic . newTypeNotAClass ( ) , argList [ 1 ] . node || errorNode ) ; } } return undefined ; } function createType ( errorNode , argList ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( errorNode ) ; const arg0Type = getTypeForArgument ( argList [ 0 ] ) . type ; if ( ! isClassInstance ( arg0Type ) || ! ClassType . isBuiltIn ( arg0Type , 'str' ) ) { return undefined ; } const className = ( arg0Type . literalValue as string ) || '_' ; const arg1Type = getTypeForArgument ( argList [ 1 ] ) . type ; if ( ! isClassInstance ( arg1Type ) || ! isTupleClass ( arg1Type ) || arg1Type . tupleTypeArguments === undefined ) { return undefined ; } const classType = ClassType . createInstantiable ( className , ParseTreeUtils . getClassFullName ( errorNode , fileInfo . moduleName , className ) , fileInfo . moduleName , fileInfo . filePath , ClassTypeFlags . None , ParseTreeUtils . getTypeSourceId ( errorNode ) , undefined , arg1Type . details . effectiveMetaclass ) ; arg1Type . tupleTypeArguments . forEach ( ( baseClass ) => { if ( isInstantiableClass ( baseClass ) || isAnyOrUnknown ( baseClass ) ) { classType . details . baseClasses . push ( baseClass ) ; } else { addExpectedClassDiagnostic ( baseClass , argList [ 1 ] . valueExpression || errorNode ) ; } } ) ; if ( ! computeMroLinearization ( classType ) ) { addError ( Localizer . Diagnostic . methodOrdering ( ) , errorNode ) ; } return classType ; } function getTypeFromConstant ( node , flags ) { let type ; if ( node . constType === KeywordType . None ) { type = ( flags & EvaluatorFlags . ExpectingType ) !== 0 ? NoneType . createType ( ) : NoneType . createInstance ( ) ; } else if ( node . constType === KeywordType . True || node . constType === KeywordType . False || node . constType === KeywordType . Debug ) { type = getBuiltInObject ( node , 'bool' ) ; if ( type && isClassInstance ( type ) ) { if ( node . constType === KeywordType . True ) { type = ClassType . cloneWithLiteral ( type , true ) ; } else if ( node . constType === KeywordType . False ) { type = ClassType . cloneWithLiteral ( type , false ) ; } } } if ( ! type ) { return undefined ; } return { type , node } ; } function getTypeFromUnaryOperation ( node , expectedType ) { const exprTypeResult = getTypeOfExpression ( node . expression ) ; let exprType = makeTopLevelTypeVarsConcrete ( exprTypeResult . type ) ; const isIncomplete = exprTypeResult . isIncomplete ; if ( isNever ( exprType ) ) { return { node , type : NeverType . create ( ) , isIncomplete } ; } const unaryOperatorMap = { [ OperatorType . Add ] : '__pos__' , [ OperatorType . Subtract ] : '__neg__' , [ OperatorType . BitwiseInvert ] : '__invert__' , } ; let type ; if ( node . operator !== OperatorType . Not ) { if ( isOptionalType ( exprType ) ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportOptionalOperand , DiagnosticRule . reportOptionalOperand , Localizer . Diagnostic . noneOperator ( ) . format ( { operator : ParseTreeUtils . printOperator ( node . operator ) , } ) , node . expression ) ; exprType = removeNoneFromUnion ( exprType ) ; } } if ( node . operator === OperatorType . Not ) { type = getBuiltInObject ( node , 'bool' ) ; if ( ! type ) { type = UnknownType . create ( ) ; } } else { if ( isAnyOrUnknown ( exprType ) ) { type = exprType ; } else { const magicMethodName = unaryOperatorMap [ node . operator ] ; type = getTypeFromMagicMethodReturn ( exprType , [ ] , magicMethodName , node , expectedType ) ; } if ( ! type ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeNotSupportUnaryOperator ( ) . format ( { operator : ParseTreeUtils . printOperator ( node . operator ) , type : printType ( exprType ) , } ) , node ) ; type = UnknownType . create ( ) ; } } if ( node . operator === OperatorType . Add || node . operator === OperatorType . Subtract ) { if ( isClassInstance ( type ) && ClassType . isBuiltIn ( type , 'int' ) && isClassInstance ( exprType ) && ClassType . isBuiltIn ( exprType , 'int' ) && typeof exprType . literalValue === 'number' ) { const value = node . operator === OperatorType . Add ? exprType . literalValue : - exprType . literalValue ! ; type = ClassType . cloneWithLiteral ( type , value ) ; } } return { type , node , isIncomplete } ; } function operatorSupportsComparisonChaining ( op ) { if ( binaryOperatorMap [ op ] && binaryOperatorMap [ op ] [ 2 ] ) { return true ; } if ( booleanOperatorMap [ op ] ) { return true ; } return false ; } function getTypeFromBinaryOperation ( node , expectedType , flags ) { const leftExpression = node . leftExpression ; let rightExpression = node . rightExpression ; let isIncomplete = false ; if ( operatorSupportsComparisonChaining ( node . operator ) ) { if ( rightExpression . nodeType === ParseNodeType . BinaryOperation && ! rightExpression . parenthesized && operatorSupportsComparisonChaining ( rightExpression . operator ) ) { getTypeFromBinaryOperation ( rightExpression , expectedType , flags ) ; rightExpression = rightExpression . leftExpression ; } } let expectedOperandType = node . operator === OperatorType . Or || node . operator === OperatorType . And ? expectedType : undefined ; let expectedLeftOperandType ; if ( node . operator === OperatorType . Multiply && expectedType && isClassInstance ( expectedType ) && ClassType . isBuiltIn ( expectedType , 'list' ) && expectedType . typeArguments && expectedType . typeArguments . length >= 1 && node . leftExpression . nodeType === ParseNodeType . List ) { expectedLeftOperandType = expectedType ; } const leftTypeResult = getTypeOfExpression ( leftExpression , expectedOperandType || expectedLeftOperandType , flags ) ; let leftType = leftTypeResult . type ; if ( ! expectedOperandType ) { if ( node . operator === OperatorType . Or || node . operator === OperatorType . And ) { expectedOperandType = leftType ; } else if ( node . operator === OperatorType . Add && node . rightExpression . nodeType === ParseNodeType . List ) { expectedOperandType = leftType ; } } const rightTypeResult = getTypeOfExpression ( rightExpression , expectedOperandType , flags ) ; let rightType = rightTypeResult . type ; if ( leftTypeResult . isIncomplete || rightTypeResult . isIncomplete ) { isIncomplete = true ; } if ( node . operator === OperatorType . BitwiseOr && ! customMetaclassSupportsMethod ( leftType , '__or__' ) && ! customMetaclassSupportsMethod ( rightType , '__ror__' ) ) { let adjustedRightType = rightType ; if ( ! isNoneInstance ( leftType ) && isNoneInstance ( rightType ) && TypeBase . isInstance ( rightType ) ) { adjustedRightType = NoneType . createType ( ) ; } if ( isUnionableType ( [ leftType , adjustedRightType ] ) ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; const unionNotationSupported = fileInfo . isStubFile || ( flags & EvaluatorFlags . AllowForwardReferences ) !== 0 || fileInfo . executionEnvironment . pythonVersion >= PythonVersion . V3_10 ; if ( ! unionNotationSupported ) { if ( ! isAnyOrUnknown ( leftType ) ) { addError ( Localizer . Diagnostic . unionSyntaxIllegal ( ) , node , node . operatorToken ) ; } } const newUnion = combineTypes ( [ leftType , adjustedRightType ] ) ; if ( isUnion ( newUnion ) ) { TypeBase . setSpecialForm ( newUnion ) ; } return { type : newUnion , node , } ; } } let isLeftOptionalType = false ; if ( booleanOperatorMap [ node . operator ] === undefined ) { if ( node . operator === OperatorType . Equals || node . operator === OperatorType . NotEquals ) { leftType = removeNoneFromUnion ( leftType ) ; } else { isLeftOptionalType = isOptionalType ( leftType ) ; } if ( node . operator === OperatorType . Equals || node . operator === OperatorType . NotEquals ) { rightType = removeNoneFromUnion ( rightType ) ; } } const diag = new DiagnosticAddendum ( ) ; let type = validateBinaryOperation ( node . operator , leftType , rightType , node , expectedType , diag ) ; if ( ! diag . isEmpty ( ) || ! type ) { if ( ! isIncomplete ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; if ( isLeftOptionalType && diag . getMessages ( ) . length === 1 ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportOptionalOperand , DiagnosticRule . reportOptionalOperand , Localizer . Diagnostic . noneOperator ( ) . format ( { operator : ParseTreeUtils . printOperator ( node . operator ) , } ) , node . leftExpression ) ; } else { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeNotSupportBinaryOperator ( ) . format ( { operator : ParseTreeUtils . printOperator ( node . operator ) , leftType : printType ( leftType ) , rightType : printType ( rightType ) , } ) + diag . getString ( ) , node ) ; } } type = UnknownType . create ( ) ; } return { type , node , isIncomplete } ; } function customMetaclassSupportsMethod ( type , methodName ) { if ( ! isInstantiableClass ( type ) ) { return false ; } const metaclass = type . details . effectiveMetaclass ; if ( ! metaclass || ! isInstantiableClass ( metaclass ) ) { return false ; } if ( ClassType . isBuiltIn ( metaclass , 'type' ) ) { return false ; } const memberInfo = lookUpClassMember ( metaclass , methodName ) ; if ( ! memberInfo ) { return false ; } if ( isInstantiableClass ( memberInfo . classType ) && ClassType . isBuiltIn ( memberInfo . classType , 'type' ) ) { return false ; } return true ; } function getTypeFromAugmentedAssignment ( node , expectedType ) { const operatorMap = { [ OperatorType . AddEqual ] : [ '__iadd__' , OperatorType . Add ] , [ OperatorType . SubtractEqual ] : [ '__isub__' , OperatorType . Subtract ] , [ OperatorType . MultiplyEqual ] : [ '__imul__' , OperatorType . Multiply ] , [ OperatorType . FloorDivideEqual ] : [ '__ifloordiv__' , OperatorType . FloorDivide ] , [ OperatorType . DivideEqual ] : [ '__itruediv__' , OperatorType . Divide ] , [ OperatorType . ModEqual ] : [ '__imod__' , OperatorType . Mod ] , [ OperatorType . PowerEqual ] : [ '__ipow__' , OperatorType . Power ] , [ OperatorType . MatrixMultiplyEqual ] : [ '__imatmul__' , OperatorType . MatrixMultiply ] , [ OperatorType . BitwiseAndEqual ] : [ '__iand__' , OperatorType . BitwiseAnd ] , [ OperatorType . BitwiseOrEqual ] : [ '__ior__' , OperatorType . BitwiseOr ] , [ OperatorType . BitwiseXorEqual ] : [ '__ixor__' , OperatorType . BitwiseXor ] , [ OperatorType . LeftShiftEqual ] : [ '__ilshift__' , OperatorType . LeftShift ] , [ OperatorType . RightShiftEqual ] : [ '__irshift__' , OperatorType . RightShift ] , } ; let type ; const diag = new DiagnosticAddendum ( ) ; const leftTypeResult = getTypeOfExpression ( node . leftExpression ) ; const leftType = leftTypeResult . type ; const rightTypeResult = getTypeOfExpression ( node . rightExpression ) ; const rightType = rightTypeResult . type ; const isIncomplete = ! ! rightTypeResult . isIncomplete || ! ! leftTypeResult . isIncomplete ; if ( isNever ( leftType ) || isNever ( rightType ) ) { return { node , type : NeverType . create ( ) , isIncomplete } ; } type = mapSubtypesExpandTypeVars ( leftType , undefined , ( leftSubtypeExpanded , leftSubtypeUnexpanded ) => { return mapSubtypesExpandTypeVars ( rightType , getTypeCondition ( leftSubtypeExpanded ) , ( rightSubtypeExpanded , rightSubtypeUnexpanded ) => { if ( isAnyOrUnknown ( leftSubtypeUnexpanded ) || isAnyOrUnknown ( rightSubtypeUnexpanded ) ) { if ( isUnknown ( leftSubtypeUnexpanded ) || isUnknown ( rightSubtypeUnexpanded ) ) { return UnknownType . create ( ) ; } else { return AnyType . create ( ) ; } } const magicMethodName = operatorMap [ node . operator ] [ 0 ] ; let returnType = getTypeFromMagicMethodReturn ( leftSubtypeUnexpanded , [ rightSubtypeUnexpanded ] , magicMethodName , node , expectedType ) ; if ( ! returnType && leftSubtypeUnexpanded !== leftSubtypeExpanded ) { returnType = getTypeFromMagicMethodReturn ( leftSubtypeExpanded , [ rightSubtypeUnexpanded ] , magicMethodName , node , expectedType ) ; } if ( ! returnType && rightSubtypeUnexpanded !== rightSubtypeExpanded ) { returnType = getTypeFromMagicMethodReturn ( leftSubtypeExpanded , [ rightSubtypeExpanded ] , magicMethodName , node , expectedType ) ; } if ( ! returnType ) { const binaryOperator = operatorMap [ node . operator ] [ 1 ] ; returnType = validateBinaryOperation ( binaryOperator , leftSubtypeUnexpanded , rightSubtypeUnexpanded , node , expectedType , diag ) ; } return returnType ; } ) ; } ) ; if ( ! diag . isEmpty ( ) || ! type || isNever ( type ) ) { if ( ! isIncomplete ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeNotSupportBinaryOperator ( ) . format ( { operator : ParseTreeUtils . printOperator ( node . operator ) , leftType : printType ( leftType ) , rightType : printType ( rightType ) , } ) + diag . getString ( ) , node ) ; } type = UnknownType . create ( ) ; } return { node , type , isIncomplete } ; } function validateBinaryOperation ( operator , leftType , rightType , errorNode , expectedType , diag ) { let type ; let concreteLeftType = makeTopLevelTypeVarsConcrete ( leftType ) ; if ( isNever ( leftType ) || isNever ( rightType ) ) { return NeverType . create ( ) ; } if ( booleanOperatorMap [ operator ] !== undefined ) { if ( operator === OperatorType . And ) { if ( ! canBeTruthy ( concreteLeftType ) ) { return leftType ; } if ( ! canBeFalsy ( concreteLeftType ) ) { return rightType ; } concreteLeftType = removeTruthinessFromType ( concreteLeftType ) ; } else if ( operator === OperatorType . Or ) { if ( ! canBeFalsy ( concreteLeftType ) ) { return leftType ; } if ( ! canBeTruthy ( concreteLeftType ) ) { return rightType ; } concreteLeftType = removeFalsinessFromType ( concreteLeftType ) ; } if ( operator === OperatorType . In || operator === OperatorType . NotIn ) { type = mapSubtypesExpandTypeVars ( rightType , undefined , ( rightSubtypeExpanded , rightSubtypeUnexpanded ) => { return mapSubtypesExpandTypeVars ( concreteLeftType , getTypeCondition ( rightSubtypeExpanded ) , ( leftSubtype ) => { if ( isAnyOrUnknown ( leftSubtype ) || isAnyOrUnknown ( rightSubtypeUnexpanded ) ) { if ( isUnknown ( leftSubtype ) || isUnknown ( rightSubtypeUnexpanded ) ) { return UnknownType . create ( ) ; } else { return AnyType . create ( ) ; } } let returnType = getTypeFromMagicMethodReturn ( rightSubtypeExpanded , [ leftSubtype ] , '__contains__' , errorNode , undefined ) ; if ( ! returnType ) { const iteratorType = getTypeFromIterator ( rightSubtypeExpanded , false , undefined ) ; if ( iteratorType && canAssignType ( iteratorType , leftSubtype ) ) { returnType = getBuiltInObject ( errorNode , 'bool' ) ; } } if ( ! returnType ) { diag . addMessage ( Localizer . Diagnostic . typeNotSupportBinaryOperator ( ) . format ( { operator : ParseTreeUtils . printOperator ( operator ) , leftType : printType ( leftSubtype ) , rightType : printType ( rightSubtypeExpanded ) , } ) ) ; } return returnType ; } ) ; } ) ; if ( type && ! isNever ( type ) ) { type = getBuiltInObject ( errorNode , 'bool' ) ; } } else { type = mapSubtypesExpandTypeVars ( concreteLeftType , undefined , ( leftSubtypeExpanded , leftSubtypeUnexpanded ) => { return mapSubtypesExpandTypeVars ( rightType , getTypeCondition ( leftSubtypeExpanded ) , ( rightSubtypeExpanded , rightSubtypeUnexpanded ) => { if ( operator === OperatorType . And || operator === OperatorType . Or ) { return removeNoReturnFromUnion ( combineTypes ( [ leftSubtypeUnexpanded , rightSubtypeUnexpanded ] ) ) ; } return getBuiltInObject ( errorNode , 'bool' ) ; } ) ; } ) ; } } else if ( binaryOperatorMap [ operator ] ) { type = mapSubtypesExpandTypeVars ( leftType , undefined , ( leftSubtypeExpanded , leftSubtypeUnexpanded ) => { return mapSubtypesExpandTypeVars ( rightType , getTypeCondition ( leftSubtypeExpanded ) , ( rightSubtypeExpanded , rightSubtypeUnexpanded ) => { if ( isAnyOrUnknown ( leftSubtypeUnexpanded ) || isAnyOrUnknown ( rightSubtypeUnexpanded ) ) { if ( isUnknown ( leftSubtypeUnexpanded ) || isUnknown ( rightSubtypeUnexpanded ) ) { return UnknownType . create ( ) ; } else { return AnyType . create ( ) ; } } if ( operator === OperatorType . Add && isClassInstance ( leftSubtypeExpanded ) && isTupleClass ( leftSubtypeExpanded ) && leftSubtypeExpanded . tupleTypeArguments && ! isOpenEndedTupleClass ( leftSubtypeExpanded ) && isClassInstance ( rightSubtypeExpanded ) && isTupleClass ( rightSubtypeExpanded ) && rightSubtypeExpanded . tupleTypeArguments && ! isOpenEndedTupleClass ( rightSubtypeExpanded ) && tupleClassType && isInstantiableClass ( tupleClassType ) ) { return ClassType . cloneAsInstance ( specializeTupleClass ( tupleClassType , [ ... leftSubtypeExpanded . tupleTypeArguments , ... rightSubtypeExpanded . tupleTypeArguments , ] ) ) ; } const magicMethodName = binaryOperatorMap [ operator ] [ 0 ] ; let resultType = getTypeFromMagicMethodReturn ( convertFunctionToObject ( leftSubtypeUnexpanded ) , [ rightSubtypeUnexpanded ] , magicMethodName , errorNode , expectedType ) ; if ( ! resultType && leftSubtypeUnexpanded !== leftSubtypeExpanded ) { resultType = getTypeFromMagicMethodReturn ( convertFunctionToObject ( leftSubtypeExpanded ) , [ rightSubtypeUnexpanded ] , magicMethodName , errorNode , expectedType ) ; } if ( ! resultType && rightSubtypeUnexpanded !== rightSubtypeExpanded ) { resultType = getTypeFromMagicMethodReturn ( convertFunctionToObject ( leftSubtypeExpanded ) , [ rightSubtypeExpanded ] , magicMethodName , errorNode , expectedType ) ; } if ( ! resultType ) { const altMagicMethodName = binaryOperatorMap [ operator ] [ 1 ] ; resultType = getTypeFromMagicMethodReturn ( convertFunctionToObject ( rightSubtypeUnexpanded ) , [ leftSubtypeUnexpanded ] , altMagicMethodName , errorNode , expectedType ) ; if ( ! resultType && rightSubtypeUnexpanded !== rightSubtypeExpanded ) { resultType = getTypeFromMagicMethodReturn ( convertFunctionToObject ( rightSubtypeExpanded ) , [ leftSubtypeUnexpanded ] , altMagicMethodName , errorNode , expectedType ) ; } if ( ! resultType && leftSubtypeUnexpanded !== leftSubtypeExpanded ) { resultType = getTypeFromMagicMethodReturn ( convertFunctionToObject ( rightSubtypeExpanded ) , [ leftSubtypeExpanded ] , altMagicMethodName , errorNode , expectedType ) ; } } if ( ! resultType ) { diag . addMessage ( Localizer . Diagnostic . typeNotSupportBinaryOperator ( ) . format ( { operator : ParseTreeUtils . printOperator ( operator ) , leftType : printType ( leftSubtypeExpanded ) , rightType : printType ( rightSubtypeExpanded ) , } ) ) ; } return resultType ; } ) ; } ) ; } return type && isNever ( type ) ? undefined : type ; } function getTypeFromMagicMethodReturn ( objType , args , magicMethodName , errorNode , expectedType ) { let magicMethodSupported = true ; const handleSubtype = ( subtype ) => { let magicMethodType ; const concreteSubtype = makeTopLevelTypeVarsConcrete ( subtype ) ; if ( isClassInstance ( concreteSubtype ) ) { magicMethodType = getTypeFromObjectMember ( errorNode , concreteSubtype , magicMethodName , undefined , undefined , MemberAccessFlags . SkipAttributeAccessOverride , subtype ) ?. type ; } else if ( isInstantiableClass ( concreteSubtype ) ) { magicMethodType = getTypeFromClassMember ( errorNode , concreteSubtype , magicMethodName , undefined , undefined , MemberAccessFlags . SkipAttributeAccessOverride | MemberAccessFlags . ConsiderMetaclassOnly ) ?. type ; } if ( magicMethodType ) { const functionArgs = args . map ( ( arg ) => { return { argumentCategory : ArgumentCategory . Simple , type : arg , } ; } ) ; let callResult ; useSpeculativeMode ( errorNode , ( ) => { callResult = validateCallArguments ( errorNode , functionArgs , magicMethodType ! , undefined , true , expectedType ) ; } ) ; if ( callResult ! . argumentErrors ) { magicMethodSupported = false ; } return callResult ! . returnType ; } magicMethodSupported = false ; return undefined ; } ; const returnType = mapSubtypes ( objType , ( subtype ) => { if ( isAnyOrUnknown ( subtype ) ) { return subtype ; } if ( isClassInstance ( subtype ) || isInstantiableClass ( subtype ) || isTypeVar ( subtype ) ) { return handleSubtype ( subtype ) ; } else if ( isNoneInstance ( subtype ) ) { const obj = getBuiltInObject ( errorNode , 'object' ) ; if ( isClassInstance ( obj ) ) { return handleSubtype ( obj ) ; } } magicMethodSupported = false ; return undefined ; } ) ; if ( ! magicMethodSupported ) { return undefined ; } return returnType ; } function convertFunctionToObject ( type ) { if ( isFunction ( type ) || isOverloadedFunction ( type ) ) { if ( objectType ) { return objectType ; } } return type ; } function getTypeFromArrowCallable ( node , flags ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; if ( ! fileInfo . isStubFile && fileInfo . executionEnvironment . pythonVersion < PythonVersion . V3_11 && ( flags & EvaluatorFlags . NotParsedByInterpreter ) === 0 ) { addError ( Localizer . Diagnostic . arrowCallableIllegal ( ) , node ) ; } const isIncomplete = false ; const functionType = FunctionType . createInstantiable ( '' , '' , '' , FunctionTypeFlags . None ) ; const enclosingScope = ParseTreeUtils . getEnclosingClassOrFunction ( node ) ; functionType . details . typeVarScopeId = enclosingScope ? getScopeIdForNode ( enclosingScope ) : WildcardTypeVarScopeId ; const returnAnnotationOptions = { } ; if ( ( flags & EvaluatorFlags . AssociateTypeVarsWithCurrentScope ) !== 0 ) { returnAnnotationOptions . associateTypeVarsWithScope = true ; } let returnType = getTypeOfAnnotation ( node . returnTypeAnnotation , returnAnnotationOptions ) ; if ( node . isAsync ) { functionType . details . flags |= FunctionTypeFlags . Async ; const awaitableType = getTypingType ( node , 'Awaitable' ) ; if ( awaitableType && isInstantiableClass ( awaitableType ) ) { returnType = ClassType . cloneForSpecialization ( ClassType . cloneAsInstance ( awaitableType ) , [ returnType ] , true ) ; } else { returnType = UnknownType . create ( ) ; } } functionType . details . declaredReturnType = returnType ; let addPositionalOnly = true ; const paramAnnotationOptions = { allowParamSpec : true , allowTypeVarTuple : true , } ; if ( ( flags & EvaluatorFlags . AssociateTypeVarsWithCurrentScope ) !== 0 ) { paramAnnotationOptions . associateTypeVarsWithScope = true ; } node . parameters . forEach ( ( param , paramIndex ) => { const paramType = getTypeOfAnnotation ( param . typeAnnotation , paramAnnotationOptions ) ; if ( isEllipsisType ( paramType ) ) { if ( param . category !== ParameterCategory . Simple || paramIndex !== 0 || node . parameters . length > 1 ) { addError ( Localizer . Diagnostic . ellipsisContext ( ) , param . typeAnnotation ) ; FunctionType . addParameter ( functionType , { category : ParameterCategory . Simple , name : `__p${ paramIndex }` , isNameSynthesized : true , type : UnknownType . create ( ) , hasDeclaredType : true , } ) ; } else { functionType . details . flags |= FunctionTypeFlags . SkipArgsKwargsCompatibilityCheck ; FunctionType . addDefaultParameters ( functionType ) ; addPositionalOnly = false ; } } else if ( param . category === ParameterCategory . Simple ) { if ( isTypeVar ( paramType ) && paramType . details . isParamSpec ) { addError ( Localizer . Diagnostic . arrowCallableParamSpec ( ) , param . typeAnnotation ) ; } if ( isTypeVar ( paramType ) && paramType . details . isVariadic && ! paramType . isVariadicUnpacked ) { addError ( Localizer . Diagnostic . arrowCallableVariadicTypeVar ( ) , param . typeAnnotation ) ; } FunctionType . addParameter ( functionType , { category : ParameterCategory . Simple , name : `__p${ paramIndex }` , isNameSynthesized : true , type : convertToInstance ( paramType ) , hasDeclaredType : true , } ) ; } else if ( param . category === ParameterCategory . VarArgList ) { if ( ! isVariadicTypeVar ( paramType ) ) { addError ( Localizer . Diagnostic . arrowCallableNotVariadicTypeVar ( ) , param . typeAnnotation ) ; } else { if ( paramType . isVariadicUnpacked ) { addError ( Localizer . Diagnostic . arrowCallableVariadicTypeVarUnpacked ( ) , param . typeAnnotation ) ; } FunctionType . addParameter ( functionType , { category : ParameterCategory . Simple , name : `__p${ paramIndex }` , isNameSynthesized : true , type : convertToInstance ( TypeVarType . cloneForUnpacked ( paramType ) ) , hasDeclaredType : true , } ) ; } } else if ( param . category === ParameterCategory . VarArgDictionary ) { if ( ! isParamSpec ( paramType ) ) { addError ( Localizer . Diagnostic . arrowCallableNotParamSpec ( ) , param . typeAnnotation ) ; } else if ( paramIndex !== node . parameters . length - 1 ) { addError ( Localizer . Diagnostic . arrowCallableParamSpecNotLast ( ) , param . typeAnnotation ) ; } else { functionType . details . paramSpec = paramType ; } } } ) ; if ( addPositionalOnly ) { FunctionType . addParameter ( functionType , { category : ParameterCategory . Simple , type : UnknownType . create ( ) , } ) ; } return { node , type : functionType , isIncomplete } ; } function getTypeFromDictionary ( node , expectedType ) { let effectiveExpectedType = expectedType ; if ( expectedType && isUnion ( expectedType ) ) { let matchingSubtype ; doForEachSubtype ( expectedType , ( subtype ) => { if ( ! matchingSubtype ) { const subtypeResult = useSpeculativeMode ( node , ( ) => { return getTypeFromDictionaryExpected ( node , subtype ) ; } ) ; if ( subtypeResult ) { matchingSubtype = subtype ; } } } ) ; effectiveExpectedType = matchingSubtype ; } let expectedTypeDiagAddendum = undefined ; if ( effectiveExpectedType ) { expectedTypeDiagAddendum = new DiagnosticAddendum ( ) ; const result = getTypeFromDictionaryExpected ( node , effectiveExpectedType , expectedTypeDiagAddendum ) ; if ( result ) { return result ; } } const result = getTypeFromDictionaryInferred ( node , expectedType ) ! ; return { ... result , expectedTypeDiagAddendum } ; } function getTypeFromDictionaryExpected ( node , expectedType , expectedDiagAddendum ? ) { expectedType = transformPossibleRecursiveTypeAlias ( expectedType ) ; if ( ! isClassInstance ( expectedType ) ) { return undefined ; } const keyTypes = [ ] ; const valueTypes = [ ] ; let isIncomplete = false ; if ( ClassType . isTypedDictClass ( expectedType ) ) { const expectedTypedDictEntries = getTypedDictMembersForClass ( evaluatorInterface , expectedType ) ; if ( getKeyAndValueTypesFromDictionary ( node , keyTypes , valueTypes , ! ! expectedType , undefined , undefined , expectedTypedDictEntries , expectedDiagAddendum ) ) { isIncomplete = true ; } if ( ClassType . isTypedDictClass ( expectedType ) ) { const resultTypedDict = assignToTypedDict ( evaluatorInterface , expectedType , keyTypes , valueTypes , expectedDiagAddendum ) ; if ( resultTypedDict ) { return { type : resultTypedDict , node , isIncomplete , } ; } } return undefined ; } const builtInDict = getBuiltInObject ( node , 'dict' ) ; if ( ! isClassInstance ( builtInDict ) ) { return undefined ; } const dictTypeVarMap = new TypeVarMap ( getTypeVarScopeId ( builtInDict ) ) ; if ( ! populateTypeVarMapBasedOnExpectedType ( ClassType . cloneAsInstantiable ( builtInDict ) , expectedType , dictTypeVarMap , getTypeVarScopesForNode ( node ) ) ) { return undefined ; } const specializedDict = applySolvedTypeVars ( ClassType . cloneAsInstantiable ( builtInDict ) , dictTypeVarMap ) as ClassType ; if ( ! specializedDict . typeArguments || specializedDict . typeArguments . length !== 2 ) { return undefined ; } const expectedKeyType = specializedDict . typeArguments [ 0 ] ; const expectedValueType = specializedDict . typeArguments [ 1 ] ; if ( getKeyAndValueTypesFromDictionary ( node , keyTypes , valueTypes , ! ! expectedType , expectedKeyType , expectedValueType , undefined , expectedDiagAddendum ) ) { isIncomplete = true ; } const isValueTypeInvariant = isClassInstance ( expectedType ) && ( ClassType . isBuiltIn ( expectedType , 'dict' ) || ClassType . isBuiltIn ( expectedType , 'MutableMapping' ) ) ; const specializedKeyType = inferTypeArgFromExpectedType ( expectedKeyType , keyTypes , false ) ; const specializedValueType = inferTypeArgFromExpectedType ( expectedValueType , valueTypes , ! isValueTypeInvariant ) ; if ( ! specializedKeyType || ! specializedValueType ) { return undefined ; } const type = getBuiltInObject ( node , 'dict' , [ specializedKeyType , specializedValueType ] ) ; return { type , node , isIncomplete } ; } function getTypeFromDictionaryInferred ( node , expectedType ) { let keyType = expectedType ? AnyType . create ( ) : UnknownType . create ( ) ; let valueType = expectedType ? AnyType . create ( ) : UnknownType . create ( ) ; let keyTypes = [ ] ; let valueTypes = [ ] ; let isEmptyContainer = false ; let isIncomplete = false ; if ( getKeyAndValueTypesFromDictionary ( node , keyTypes , valueTypes , ! expectedType , expectedType ? AnyType . create ( ) : undefined , expectedType ? AnyType . create ( ) : undefined ) ) { isIncomplete = true ; } keyTypes = keyTypes . map ( ( t ) => stripLiteralValue ( t ) ) ; valueTypes = valueTypes . map ( ( t ) => stripLiteralValue ( t ) ) ; keyType = keyTypes . length > 0 ? combineTypes ( keyTypes ) : expectedType ? AnyType . create ( ) : UnknownType . create ( ) ; if ( valueTypes . length > 0 ) { if ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . strictDictionaryInference || ! ! expectedType ) { valueType = combineTypes ( valueTypes ) ; } else { valueType = areTypesSame ( valueTypes , true ) ? valueTypes [ 0 ] : expectedType ? AnyType . create ( ) : UnknownType . create ( ) ; } } else { valueType = expectedType ? AnyType . create ( ) : UnknownType . create ( ) ; isEmptyContainer = true ; } const dictClass = getBuiltInType ( node , 'dict' ) ; const type = isInstantiableClass ( dictClass ) ? ClassType . cloneAsInstance ( ClassType . cloneForSpecialization ( dictClass , [ keyType , valueType ] , true , undefined , undefined , isEmptyContainer ) ) : UnknownType . create ( ) ; return { type , node , isIncomplete } ; } function getKeyAndValueTypesFromDictionary ( node , keyTypes , valueTypes , limitEntryCount , expectedKeyType ? , expectedValueType ? , expectedTypedDictEntries ? , expectedDiagAddendum ? ) { let isIncomplete = false ; node . entries . forEach ( ( entryNode , index ) => { let addUnknown = true ; if ( entryNode . nodeType === ParseNodeType . DictionaryKeyEntry ) { const keyTypeResult = getTypeOfExpression ( entryNode . keyExpression , expectedKeyType ) ; if ( keyTypeResult . isIncomplete ) { isIncomplete = true ; } let keyType = keyTypeResult . type ; if ( expectedKeyType ) { const adjExpectedKeyType = makeTopLevelTypeVarsConcrete ( expectedKeyType ) ; if ( ! isAnyOrUnknown ( adjExpectedKeyType ) ) { if ( canAssignType ( adjExpectedKeyType , keyType ) ) { keyType = adjExpectedKeyType ; } } } let valueTypeResult ; if ( expectedTypedDictEntries && isClassInstance ( keyType ) && ClassType . isBuiltIn ( keyType , 'str' ) && isLiteralType ( keyType ) && expectedTypedDictEntries . has ( keyType . literalValue as string ) ) { valueTypeResult = getTypeOfExpression ( entryNode . valueExpression , expectedTypedDictEntries . get ( keyType . literalValue as string ) ! . valueType ) ; } else { valueTypeResult = getTypeOfExpression ( entryNode . valueExpression , expectedValueType ) ; } if ( expectedDiagAddendum && valueTypeResult . expectedTypeDiagAddendum ) { expectedDiagAddendum . addAddendum ( valueTypeResult . expectedTypeDiagAddendum ) ; } const valueType = valueTypeResult . type ; if ( valueTypeResult . isIncomplete ) { isIncomplete = true ; } if ( ! limitEntryCount || index < maxEntriesToUseForInference ) { keyTypes . push ( keyType ) ; valueTypes . push ( valueType ) ; } addUnknown = false ; } else if ( entryNode . nodeType === ParseNodeType . DictionaryExpandEntry ) { const unexpandedTypeResult = getTypeOfExpression ( entryNode . expandExpression ) ; if ( unexpandedTypeResult . isIncomplete ) { isIncomplete = true ; } const unexpandedType = unexpandedTypeResult . type ; if ( isAnyOrUnknown ( unexpandedType ) ) { addUnknown = false ; } else { const mappingType = getTypingType ( node , 'Mapping' ) ; if ( mappingType && isInstantiableClass ( mappingType ) ) { const mappingTypeVarMap = new TypeVarMap ( getTypeVarScopeId ( mappingType ) ) ; if ( canAssignType ( ClassType . cloneAsInstance ( mappingType ) , unexpandedType , undefined , mappingTypeVarMap ) ) { const specializedMapping = applySolvedTypeVars ( mappingType , mappingTypeVarMap ) as ClassType ; const typeArgs = specializedMapping . typeArguments ; if ( typeArgs && typeArgs . length >= 2 ) { if ( ! limitEntryCount || index < maxEntriesToUseForInference ) { keyTypes . push ( typeArgs [ 0 ] ) ; valueTypes . push ( typeArgs [ 1 ] ) ; } addUnknown = false ; } } else { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . dictUnpackIsNotMapping ( ) , entryNode ) ; } } } } else if ( entryNode . nodeType === ParseNodeType . ListComprehension ) { const dictEntryTypeResult = getElementTypeFromListComprehension ( entryNode , expectedValueType , expectedKeyType ) ; const dictEntryType = dictEntryTypeResult . type ; if ( dictEntryTypeResult . isIncomplete ) { isIncomplete = true ; } if ( isClassInstance ( dictEntryType ) && isTupleClass ( dictEntryType ) ) { const typeArgs = dictEntryType . tupleTypeArguments ; if ( typeArgs && typeArgs . length === 2 ) { if ( ! limitEntryCount || index < maxEntriesToUseForInference ) { keyTypes . push ( typeArgs [ 0 ] ) ; valueTypes . push ( typeArgs [ 1 ] ) ; } addUnknown = false ; } } } if ( addUnknown ) { if ( ! limitEntryCount || index < maxEntriesToUseForInference ) { keyTypes . push ( UnknownType . create ( ) ) ; valueTypes . push ( UnknownType . create ( ) ) ; } } } ) ; return isIncomplete ; } function getTypeFromListOrSet ( node , expectedType ) { let effectiveExpectedType = expectedType ; if ( expectedType && isUnion ( expectedType ) ) { let matchingSubtype ; doForEachSubtype ( expectedType , ( subtype ) => { if ( ! matchingSubtype ) { const subtypeResult = useSpeculativeMode ( node , ( ) => { return getTypeFromListOrSetExpected ( node , subtype ) ; } ) ; if ( subtypeResult ) { matchingSubtype = subtype ; } } } ) ; effectiveExpectedType = matchingSubtype ; } if ( effectiveExpectedType ) { const result = getTypeFromListOrSetExpected ( node , effectiveExpectedType ) ; if ( result ) { return result ; } } return getTypeFromListOrSetInferred ( node , expectedType ) ; } function getTypeFromListOrSetExpected ( node , expectedType ) { const builtInClassName = node . nodeType === ParseNodeType . List ? 'list' : 'set' ; expectedType = transformPossibleRecursiveTypeAlias ( expectedType ) ; let isIncomplete = false ; if ( ! isClassInstance ( expectedType ) ) { return undefined ; } const builtInListOrSet = getBuiltInObject ( node , builtInClassName ) ; if ( ! isClassInstance ( builtInListOrSet ) ) { return undefined ; } const typeVarMap = new TypeVarMap ( getTypeVarScopeId ( builtInListOrSet ) ) ; if ( ! populateTypeVarMapBasedOnExpectedType ( ClassType . cloneAsInstantiable ( builtInListOrSet ) , expectedType , typeVarMap , getTypeVarScopesForNode ( node ) ) ) { return undefined ; } const specializedListOrSet = applySolvedTypeVars ( ClassType . cloneAsInstantiable ( builtInListOrSet ) , typeVarMap ) as ClassType ; if ( ! specializedListOrSet . typeArguments || specializedListOrSet . typeArguments . length !== 1 ) { return undefined ; } const expectedEntryType = specializedListOrSet . typeArguments [ 0 ] ; const entryTypes = [ ] ; node . entries . forEach ( ( entry ) => { let entryTypeResult ; if ( entry . nodeType === ParseNodeType . ListComprehension ) { entryTypeResult = getElementTypeFromListComprehension ( entry , expectedEntryType ) ; } else { entryTypeResult = getTypeOfExpression ( entry , expectedEntryType ) ; } entryTypes . push ( entryTypeResult . type ) ; if ( entryTypeResult . isIncomplete ) { isIncomplete = true ; } } ) ; const isExpectedTypeListOrSet = isClassInstance ( expectedType ) && ClassType . isBuiltIn ( expectedType , builtInClassName ) ; const specializedEntryType = inferTypeArgFromExpectedType ( expectedEntryType , entryTypes , ! isExpectedTypeListOrSet ) ; if ( ! specializedEntryType ) { return undefined ; } const type = getBuiltInObject ( node , builtInClassName , [ specializedEntryType ] ) ; return { type , node , isIncomplete } ; } function getTypeFromListOrSetInferred ( node , expectedType ) { const builtInClassName = node . nodeType === ParseNodeType . List ? 'list' : 'set' ; let isEmptyContainer = false ; let isIncomplete = false ; let expectedEntryType ; if ( expectedType ) { if ( isAny ( expectedType ) ) { expectedEntryType = expectedType ; } else if ( isClassInstance ( expectedType ) && ClassType . isBuiltIn ( expectedType , 'object' ) ) { expectedEntryType = AnyType . create ( ) ; } } let entryTypes = [ ] ; node . entries . forEach ( ( entry , index ) => { let entryTypeResult ; if ( entry . nodeType === ParseNodeType . ListComprehension ) { entryTypeResult = getElementTypeFromListComprehension ( entry , expectedEntryType ) ; } else { entryTypeResult = getTypeOfExpression ( entry , expectedEntryType ) ; } if ( entryTypeResult . isIncomplete ) { isIncomplete = true ; } if ( index < maxEntriesToUseForInference ) { entryTypes . push ( entryTypeResult . type ) ; } } ) ; entryTypes = entryTypes . map ( ( t ) => stripLiteralValue ( t ) ) ; let inferredEntryType = expectedType ? AnyType . create ( ) : UnknownType . create ( ) ; if ( entryTypes . length > 0 ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; if ( ( builtInClassName === 'list' && fileInfo . diagnosticRuleSet . strictListInference ) || ( builtInClassName === 'set' && fileInfo . diagnosticRuleSet . strictSetInference ) || ! ! expectedType ) { inferredEntryType = combineTypes ( entryTypes , maxSubtypesForInferredType ) ; } else { inferredEntryType = areTypesSame ( entryTypes , true ) ? entryTypes [ 0 ] : inferredEntryType ; } } else { isEmptyContainer = true ; } const listOrSetClass = getBuiltInType ( node , builtInClassName ) ; const type = isInstantiableClass ( listOrSetClass ) ? ClassType . cloneAsInstance ( ClassType . cloneForSpecialization ( listOrSetClass , [ inferredEntryType ] , true , undefined , undefined , isEmptyContainer ) ) : UnknownType . create ( ) ; return { type , node , isIncomplete } ; } function inferTypeArgFromExpectedType ( expectedType , entryTypes , isNarrowable ) { const targetTypeVar = TypeVarType . createInstance ( '__typeArg' ) ; targetTypeVar . details . isSynthesized = true ; targetTypeVar . details . boundType = expectedType ; targetTypeVar . scopeId = '__typeArgScopeId' ; let typeVarMap = new TypeVarMap ( WildcardTypeVarScopeId ) ; typeVarMap . setTypeVarType ( targetTypeVar , isNarrowable ? undefined : expectedType , expectedType ) ; if ( entryTypes . some ( ( entryType ) => ! canAssignType ( targetTypeVar , stripLiteralValue ( entryType ) , undefined , typeVarMap ) ) ) { typeVarMap = new TypeVarMap ( WildcardTypeVarScopeId ) ; typeVarMap . setTypeVarType ( targetTypeVar , isNarrowable ? undefined : expectedType , expectedType , true ) ; if ( entryTypes . some ( ( entryType ) => ! canAssignType ( targetTypeVar ! , entryType , undefined , typeVarMap ) ) ) { return undefined ; } } return applySolvedTypeVars ( targetTypeVar , typeVarMap ) ; } function getTypeFromTernary ( node , flags , expectedType ) { getTypeOfExpression ( node . testExpression ) ; const typesToCombine = [ ] ; let isIncomplete = false ; if ( isNodeReachable ( node . ifExpression ) ) { const ifType = getTypeOfExpression ( node . ifExpression , expectedType , flags ) ; typesToCombine . push ( ifType . type ) ; if ( ifType . isIncomplete ) { isIncomplete = true ; } } if ( isNodeReachable ( node . elseExpression ) ) { const elseType = getTypeOfExpression ( node . elseExpression , expectedType , flags ) ; typesToCombine . push ( elseType . type ) ; if ( elseType . isIncomplete ) { isIncomplete = true ; } } const type = removeNoReturnFromUnion ( combineTypes ( typesToCombine ) ) ; return { type , node , isIncomplete } ; } function getTypeFromYield ( node ) { let sentType ; let isIncomplete = false ; const enclosingFunction = ParseTreeUtils . getEnclosingFunction ( node ) ; if ( enclosingFunction ) { const functionTypeInfo = getTypeOfFunction ( enclosingFunction ) ; if ( functionTypeInfo ) { sentType = getDeclaredGeneratorSendType ( functionTypeInfo . functionType ) ; } } if ( node . expression ) { const exprResult = getTypeOfExpression ( node . expression ) ; if ( exprResult . isIncomplete ) { isIncomplete = true ; } } return { type : sentType || UnknownType . create ( ) , node , isIncomplete } ; } function getTypeFromYieldFrom ( node ) { const yieldFromType = getTypeOfExpression ( node . expression ) . type ; let generatorTypeArgs = getGeneratorTypeArgs ( yieldFromType ) ; let returnedType ; if ( generatorTypeArgs ) { returnedType = generatorTypeArgs . length >= 2 ? generatorTypeArgs [ 2 ] : UnknownType . create ( ) ; } else { const iterableType = getTypeFromIterable ( yieldFromType , false , node ) || UnknownType . create ( ) ; generatorTypeArgs = getGeneratorTypeArgs ( iterableType ) ; if ( generatorTypeArgs ) { returnedType = generatorTypeArgs . length >= 2 ? generatorTypeArgs [ 2 ] : UnknownType . create ( ) ; } else { returnedType = UnknownType . create ( ) ; } } return { type : returnedType || UnknownType . create ( ) , node } ; } function getTypeFromLambda ( node , expectedType ) { const functionType = FunctionType . createInstance ( '' , '' , '' , FunctionTypeFlags . None ) ; writeTypeCache ( node , functionType , EvaluatorFlags . None , false ) ; let expectedFunctionTypes = [ ] ; if ( expectedType ) { mapSubtypes ( expectedType , ( subtype ) => { if ( isFunction ( subtype ) ) { expectedFunctionTypes . push ( subtype ) ; } if ( isClassInstance ( subtype ) ) { const callMember = lookUpObjectMember ( subtype , '__call__' ) ; if ( callMember ) { const memberType = getTypeOfMember ( callMember ) ; if ( memberType && isFunction ( memberType ) ) { const boundMethod = bindFunctionToClassOrObject ( subtype , memberType ) ; if ( boundMethod ) { expectedFunctionTypes . push ( boundMethod as FunctionType ) ; } } } } return undefined ; } ) ; const lambdaParamCount = node . parameters . filter ( ( param ) => param . category === ParameterCategory . Simple && param . defaultValue === undefined ) . length ; expectedFunctionTypes = expectedFunctionTypes . filter ( ( functionType ) => { const functionParamCount = functionType . details . parameters . filter ( ( param ) => ! ! param . name ) . length ; const hasVarArgs = functionType . details . parameters . some ( ( param ) => ! ! param . name && param . category !== ParameterCategory . Simple ) ; return hasVarArgs || functionParamCount === lambdaParamCount ; } ) ; } const expectedFunctionType = expectedFunctionTypes . length > 0 ? expectedFunctionTypes [ 0 ] : undefined ; node . parameters . forEach ( ( param , index ) => { let paramType = UnknownType . create ( ) ; if ( expectedFunctionType && index < expectedFunctionType . details . parameters . length ) { paramType = FunctionType . getEffectiveParameterType ( expectedFunctionType , index ) ; } if ( param . name ) { writeTypeCache ( param . name , transformVariadicParamType ( node , param . category , paramType ) , EvaluatorFlags . None , false ) ; } if ( param . defaultValue ) { getTypeOfExpression ( param . defaultValue , undefined , EvaluatorFlags . ConvertEllipsisToAny ) ; } const functionParam = { category : param . category , name : param . name ? param . name . value : undefined , hasDefault : ! ! param . defaultValue , defaultValueExpression : param . defaultValue , hasDeclaredType : true , type : paramType , } ; FunctionType . addParameter ( functionType , functionParam ) ; } ) ; const expectedReturnType = expectedFunctionType ? getFunctionEffectiveReturnType ( expectedFunctionType ) : undefined ; if ( speculativeTypeTracker . isSpeculative ( node ) ) { useSpeculativeMode ( node . expression , ( ) => { functionType . inferredReturnType = getTypeOfExpression ( node . expression , expectedReturnType ) . type ; } , false ) ; } else { functionType . inferredReturnType = getTypeOfExpression ( node . expression , expectedReturnType ) . type ; } return { type : functionType , node } ; } function getTypeFromListComprehension ( node , expectedType ? ) { let isIncomplete = false ; const elementTypeResult = getElementTypeFromListComprehension ( node ) ; if ( elementTypeResult . isIncomplete ) { isIncomplete = true ; } const elementType = elementTypeResult . type ; let isAsync = node . comprehensions . some ( ( comp ) => { return ( ( comp . nodeType === ParseNodeType . ListComprehensionFor && comp . isAsync ) || ( comp . nodeType === ParseNodeType . ListComprehensionIf && comp . testExpression . nodeType === ParseNodeType . Await ) ) ; } ) ; let type = UnknownType . create ( ) ; if ( node . expression . nodeType === ParseNodeType . Await ) { isAsync = true ; } if ( ! isAsync && expectedType && isClassInstance ( expectedType ) && ClassType . isBuiltIn ( expectedType , 'AsyncGenerator' ) ) { isAsync = true ; } const builtInIteratorType = getTypingType ( node , isAsync ? 'AsyncGenerator' : 'Generator' ) ; if ( builtInIteratorType && isInstantiableClass ( builtInIteratorType ) ) { type = ClassType . cloneAsInstance ( ClassType . cloneForSpecialization ( builtInIteratorType , isAsync ? [ elementType , NoneType . createInstance ( ) ] : [ elementType , NoneType . createInstance ( ) , NoneType . createInstance ( ) ] , true ) ) ; } return { type , node , isIncomplete } ; } function reportPossibleUnknownAssignment ( diagLevel , rule , target , type , errorNode , ignoreEmptyContainers ) { if ( diagLevel === 'none' ) { return ; } const nameValue = target . value ; const simplifiedType = removeUnbound ( type ) ; if ( isUnknown ( simplifiedType ) ) { addDiagnostic ( diagLevel , rule , Localizer . Diagnostic . typeUnknown ( ) . format ( { name : nameValue } ) , errorNode ) ; } else if ( isPartlyUnknown ( simplifiedType ) ) { if ( ! ignoreEmptyContainers || ! isClassInstance ( type ) || ! type . isEmptyContainer ) { const diagAddendum = new DiagnosticAddendum ( ) ; diagAddendum . addMessage ( Localizer . DiagnosticAddendum . typeOfSymbol ( ) . format ( { name : nameValue , type : printType ( simplifiedType , true ) , } ) ) ; addDiagnostic ( diagLevel , rule , Localizer . Diagnostic . typePartiallyUnknown ( ) . format ( { name : nameValue } ) + diagAddendum . getString ( ) , errorNode ) ; } } } function getElementTypeFromListComprehension ( node , expectedValueOrElementType ? , expectedKeyType ? ) { let isIncomplete = false ; for ( const comprehension of node . comprehensions ) { if ( comprehension . nodeType === ParseNodeType . ListComprehensionFor ) { const iterableTypeResult = getTypeOfExpression ( comprehension . iterableExpression ) ; if ( iterableTypeResult . isIncomplete ) { isIncomplete = true ; } const iterableType = stripLiteralValue ( iterableTypeResult . type ) ; const itemType = getTypeFromIterator ( iterableType , ! ! comprehension . isAsync , comprehension . iterableExpression ) || UnknownType . create ( ) ; const targetExpr = comprehension . targetExpression ; assignTypeToExpression ( targetExpr , itemType , ! ! iterableTypeResult . isIncomplete , comprehension . iterableExpression ) ; } else { assert ( comprehension . nodeType === ParseNodeType . ListComprehensionIf ) ; if ( ! speculativeTypeTracker . isSpeculative ( comprehension . testExpression ) ) { getTypeOfExpression ( comprehension . testExpression ) ; } } } let type = UnknownType . create ( ) ; if ( node . expression . nodeType === ParseNodeType . DictionaryKeyEntry ) { const keyTypeResult = getTypeOfExpression ( node . expression . keyExpression , expectedKeyType ) ; if ( keyTypeResult . isIncomplete ) { isIncomplete = true ; } let keyType = keyTypeResult . type ; if ( ! expectedKeyType || ! containsLiteralType ( expectedKeyType ) ) { keyType = stripLiteralValue ( keyType ) ; } const valueTypeResult = getTypeOfExpression ( node . expression . valueExpression , expectedValueOrElementType ) ; if ( valueTypeResult . isIncomplete ) { isIncomplete = true ; } let valueType = valueTypeResult . type ; if ( ! expectedValueOrElementType || ! containsLiteralType ( expectedValueOrElementType ) ) { valueType = stripLiteralValue ( valueType ) ; } type = makeTupleObject ( [ keyType , valueType ] ) ; } else if ( node . expression . nodeType === ParseNodeType . DictionaryExpandEntry ) { getTypeOfExpression ( node . expression . expandExpression , expectedValueOrElementType ) ; } else if ( isExpressionNode ( node ) ) { const exprTypeResult = getTypeOfExpression ( node . expression as ExpressionNode , expectedValueOrElementType ) ; if ( exprTypeResult . isIncomplete ) { isIncomplete = true ; } type = exprTypeResult . type ; } return { type , node , isIncomplete } ; } function getTypeFromSlice ( node ) { if ( node . startValue ) { getTypeOfExpression ( node . startValue ) ; } if ( node . endValue ) { getTypeOfExpression ( node . endValue ) ; } if ( node . stepValue ) { getTypeOfExpression ( node . stepValue ) ; } return { type : getBuiltInObject ( node , 'slice' ) , node } ; } function validateTypeArg ( argResult , allowEmptyTuple = false , allowVariadicTypeVar = false , allowParamSpec = false , allowTypeArgList = false ) { if ( argResult . typeList ) { if ( ! allowTypeArgList ) { addError ( Localizer . Diagnostic . typeArgListNotAllowed ( ) , argResult . node ) ; return false ; } else { argResult . typeList ! . forEach ( ( typeArg ) => { validateTypeArg ( typeArg ) ; } ) ; } } if ( isEllipsisType ( argResult . type ) ) { if ( ! allowTypeArgList ) { addError ( Localizer . Diagnostic . ellipsisContext ( ) , argResult . node ) ; return false ; } } if ( isModule ( argResult . type ) ) { addError ( Localizer . Diagnostic . moduleAsType ( ) , argResult . node ) ; return false ; } if ( isParamSpec ( argResult . type ) ) { if ( ! allowParamSpec ) { addError ( Localizer . Diagnostic . paramSpecContext ( ) , argResult . node ) ; return false ; } } if ( isVariadicTypeVar ( argResult . type ) && ! argResult . type . isVariadicInUnion ) { if ( ! allowVariadicTypeVar ) { addError ( Localizer . Diagnostic . typeVarTupleContext ( ) , argResult . node ) ; return false ; } else { validateVariadicTypeVarIsUnpacked ( argResult . type , argResult . node ) ; } } if ( ! allowEmptyTuple && argResult . isEmptyTupleShorthand ) { addError ( Localizer . Diagnostic . zeroLengthTupleNotAllowed ( ) , argResult . node ) ; return false ; } return true ; } function createCallableType ( typeArgs , errorNode ) { const functionType = FunctionType . createInstantiable ( '' , '' , '' , FunctionTypeFlags . None ) ; TypeBase . setSpecialForm ( functionType ) ; functionType . details . declaredReturnType = UnknownType . create ( ) ; const enclosingScope = ParseTreeUtils . getEnclosingClassOrFunction ( errorNode ) ; functionType . details . typeVarScopeId = enclosingScope ? getScopeIdForNode ( enclosingScope ) : WildcardTypeVarScopeId ; if ( typeArgs && typeArgs . length > 0 ) { if ( typeArgs [ 0 ] . typeList ) { const typeList = typeArgs [ 0 ] . typeList ; let sawVariadic = false ; let reportedVariadicError = false ; typeList . forEach ( ( entry , index ) => { let entryType = entry . type ; let paramCategory = ParameterCategory . Simple ; const paramName = `__p${ index . toString ( ) }` ; if ( isVariadicTypeVar ( entryType ) ) { if ( sawVariadic ) { if ( ! reportedVariadicError ) { addError ( Localizer . Diagnostic . variadicTypeArgsTooMany ( ) , entry . node ) ; reportedVariadicError = true ; } } sawVariadic = true ; validateVariadicTypeVarIsUnpacked ( entryType , entry . node ) ; paramCategory = ParameterCategory . Simple ; } else if ( ! validateTypeArg ( entry ) ) { entryType = UnknownType . create ( ) ; } FunctionType . addParameter ( functionType , { category : paramCategory , name : paramName , isNameSynthesized : true , type : convertToInstance ( entryType ) , hasDeclaredType : true , } ) ; } ) ; FunctionType . addParameter ( functionType , { category : ParameterCategory . Simple , isNameSynthesized : false , type : UnknownType . create ( ) , } ) ; } else if ( isEllipsisType ( typeArgs [ 0 ] . type ) ) { FunctionType . addDefaultParameters ( functionType ) ; functionType . details . flags |= FunctionTypeFlags . SkipArgsKwargsCompatibilityCheck ; } else if ( isParamSpec ( typeArgs [ 0 ] . type ) ) { functionType . details . paramSpec = typeArgs [ 0 ] . type ; } else { if ( isInstantiableClass ( typeArgs [ 0 ] . type ) && ClassType . isBuiltIn ( typeArgs [ 0 ] . type , 'Concatenate' ) ) { const concatTypeArgs = typeArgs [ 0 ] . type . typeArguments ; if ( concatTypeArgs && concatTypeArgs . length > 0 ) { concatTypeArgs . forEach ( ( typeArg , index ) => { if ( index === concatTypeArgs . length - 1 ) { if ( isParamSpec ( typeArg ) ) { functionType . details . paramSpec = typeArg ; } } else { FunctionType . addParameter ( functionType , { category : ParameterCategory . Simple , name : `__p${ index }` , isNameSynthesized : true , hasDeclaredType : true , type : typeArg , } ) ; } } ) ; } } else { addError ( Localizer . Diagnostic . callableFirstArg ( ) , typeArgs [ 0 ] . node ) ; } } if ( typeArgs . length > 1 ) { let typeArg1Type = typeArgs [ 1 ] . type ; if ( ! validateTypeArg ( typeArgs [ 1 ] ) ) { typeArg1Type = UnknownType . create ( ) ; } functionType . details . declaredReturnType = convertToInstance ( typeArg1Type ) ; } else { const fileInfo = AnalyzerNodeInfo . getFileInfo ( errorNode ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . callableSecondArg ( ) , errorNode ) ; functionType . details . declaredReturnType = UnknownType . create ( ) ; } if ( typeArgs . length > 2 ) { addError ( Localizer . Diagnostic . callableExtraArgs ( ) , typeArgs [ 2 ] . node ) ; } } else { FunctionType . addDefaultParameters ( functionType , true ) ; functionType . details . flags |= FunctionTypeFlags . SkipArgsKwargsCompatibilityCheck ; } return functionType ; } function createOptionalType ( classType , errorNode , typeArgs , flags ) { if ( ! typeArgs ) { if ( ( flags & EvaluatorFlags . ExpectingTypeAnnotation ) !== 0 ) { addError ( Localizer . Diagnostic . optionalExtraArgs ( ) , errorNode ) ; return UnknownType . create ( ) ; } return classType ; } if ( typeArgs . length > 1 ) { addError ( Localizer . Diagnostic . optionalExtraArgs ( ) , errorNode ) ; return UnknownType . create ( ) ; } let typeArg0Type = typeArgs [ 0 ] . type ; if ( ! validateTypeArg ( typeArgs [ 0 ] ) ) { typeArg0Type = UnknownType . create ( ) ; } else if ( ! TypeBase . isInstantiable ( typeArg0Type ) ) { addExpectedClassDiagnostic ( typeArg0Type , typeArgs [ 0 ] . node ) ; typeArg0Type = UnknownType . create ( ) ; } const optionalType = combineTypes ( [ typeArg0Type , NoneType . createType ( ) ] ) ; if ( isUnion ( optionalType ) ) { TypeBase . setSpecialForm ( optionalType ) ; } return optionalType ; } function cloneBuiltinObjectWithLiteral ( node , builtInName , value ) { const type = getBuiltInObject ( node , builtInName ) ; if ( isClassInstance ( type ) ) { return ClassType . cloneWithLiteral ( type , value ) ; } return UnknownType . create ( ) ; } function cloneBuiltinClassWithLiteral ( node , builtInName , value ) { const type = getBuiltInType ( node , builtInName ) ; if ( isInstantiableClass ( type ) ) { return ClassType . cloneWithLiteral ( type , value ) ; } return UnknownType . create ( ) ; } function createLiteralType ( node , flags ) { if ( node . items . length === 0 ) { addError ( Localizer . Diagnostic . literalEmptyArgs ( ) , node . baseExpression ) ; return UnknownType . create ( ) ; } const literalTypes = [ ] ; for ( const item of node . items ) { let type ; const itemExpr = item . valueExpression ; if ( item . argumentCategory !== ArgumentCategory . Simple ) { addError ( Localizer . Diagnostic . unpackedArgInTypeArgument ( ) , itemExpr ) ; type = UnknownType . create ( ) ; } else if ( item . name ) { addError ( Localizer . Diagnostic . keywordArgInTypeArgument ( ) , itemExpr ) ; type = UnknownType . create ( ) ; } else if ( itemExpr . nodeType === ParseNodeType . StringList ) { const isBytes = ( itemExpr . strings [ 0 ] . token . flags & StringTokenFlags . Bytes ) !== 0 ; const value = itemExpr . strings . map ( ( s ) => s . value ) . join ( '' ) ; if ( isBytes ) { type = cloneBuiltinClassWithLiteral ( node , 'bytes' , value ) ; } else { type = cloneBuiltinClassWithLiteral ( node , 'str' , value ) ; } } else if ( itemExpr . nodeType === ParseNodeType . Number ) { if ( ! itemExpr . isImaginary && itemExpr . isInteger ) { type = cloneBuiltinClassWithLiteral ( node , 'int' , itemExpr . value ) ; } } else if ( itemExpr . nodeType === ParseNodeType . Constant ) { if ( itemExpr . constType === KeywordType . True ) { type = cloneBuiltinClassWithLiteral ( node , 'bool' , true ) ; } else if ( itemExpr . constType === KeywordType . False ) { type = cloneBuiltinClassWithLiteral ( node , 'bool' , false ) ; } else if ( itemExpr . constType === KeywordType . None ) { type = NoneType . createType ( ) ; } } else if ( itemExpr . nodeType === ParseNodeType . UnaryOperation && itemExpr . operator === OperatorType . Subtract ) { if ( itemExpr . expression . nodeType === ParseNodeType . Number ) { if ( ! itemExpr . expression . isImaginary && itemExpr . expression . isInteger ) { type = cloneBuiltinClassWithLiteral ( node , 'int' , - itemExpr . expression . value ) ; } } } if ( ! type ) { const exprType = getTypeOfExpression ( itemExpr ) ; if ( isClassInstance ( exprType . type ) && ClassType . isEnumClass ( exprType . type ) && exprType . type . literalValue !== undefined ) { type = ClassType . cloneAsInstantiable ( exprType . type ) ; } else { let isLiteralType = true ; doForEachSubtype ( exprType . type , ( subtype ) => { if ( ! isInstantiableClass ( subtype ) || subtype . literalValue === undefined ) { isLiteralType = false ; } } ) ; if ( isLiteralType ) { type = exprType . type ; } } } if ( ! type ) { addError ( Localizer . Diagnostic . literalUnsupportedType ( ) , item ) ; type = UnknownType . create ( ) ; } literalTypes . push ( type ) ; } return combineTypes ( literalTypes ) ; } function createClassVarType ( classType , errorNode , typeArgs , flags ) { if ( flags & EvaluatorFlags . ClassVarDisallowed ) { addError ( Localizer . Diagnostic . classVarNotAllowed ( ) , errorNode ) ; return AnyType . create ( ) ; } if ( ! typeArgs ) { return classType ; } else if ( typeArgs . length === 0 ) { addError ( Localizer . Diagnostic . classVarFirstArgMissing ( ) , errorNode ) ; return UnknownType . create ( ) ; } else if ( typeArgs . length > 1 ) { addError ( Localizer . Diagnostic . classVarTooManyArgs ( ) , typeArgs [ 1 ] . node ) ; return UnknownType . create ( ) ; } const type = typeArgs [ 0 ] . type ; if ( requiresSpecialization ( type , true ) ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( errorNode ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . classVarWithTypeVar ( ) , typeArgs [ 0 ] . node ?? errorNode ) ; } return type ; } function createTypeGuardType ( errorNode , classType , typeArgs ) { if ( ! typeArgs || typeArgs . length < 1 || typeArgs . length > 2 ) { addError ( Localizer . Diagnostic . typeGuardArgCount ( ) , errorNode ) ; return UnknownType . create ( ) ; } const convertedTypeArgs = typeArgs . map ( ( typeArg ) => { return convertToInstance ( validateTypeArg ( typeArg ) ? typeArg . type : UnknownType . create ( ) ) ; } ) ; return ClassType . cloneForSpecialization ( classType , convertedTypeArgs , true ) ; } function createSelfType ( classType , errorNode , typeArgs ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( errorNode ) ; if ( typeArgs ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeArgsExpectingNone ( ) . format ( { name : classType . details . name , } ) , typeArgs [ 0 ] . node ?? errorNode ) ; } const enclosingClass = ParseTreeUtils . getEnclosingClass ( errorNode ) ; const enclosingClassTypeResult = enclosingClass ? getTypeOfClass ( enclosingClass ) : undefined ; if ( ! enclosingClassTypeResult ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . selfTypeContext ( ) , errorNode ) ; return UnknownType . create ( ) ; } const enclosingFunction = ParseTreeUtils . getEnclosingFunction ( errorNode ) ; if ( enclosingFunction ) { const functionFlags = getFunctionFlagsFromDecorators ( enclosingFunction , true ) ; if ( functionFlags & FunctionTypeFlags . StaticMethod ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . selfTypeContext ( ) , errorNode ) ; return UnknownType . create ( ) ; } if ( enclosingFunction . parameters . length > 0 ) { const firstParamTypeAnnotation = getTypeAnnotationForParameter ( enclosingFunction , 0 ) ; if ( firstParamTypeAnnotation && ! ParseTreeUtils . isNodeContainedWithin ( errorNode , firstParamTypeAnnotation ) ) { const annotationType = getTypeOfAnnotation ( firstParamTypeAnnotation , { associateTypeVarsWithScope : true , disallowRecursiveTypeAlias : true , } ) ; if ( ! isTypeVar ( annotationType ) || ! annotationType . details . isSynthesizedSelf ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . selfTypeWithTypedSelfOrCls ( ) , errorNode ) ; } } } } return synthesizeTypeVarForSelfCls ( enclosingClassTypeResult . classType , true ) ; } function createRequiredType ( classType , errorNode , isRequired , typeArgs , flags ) { if ( ! typeArgs && ( flags & EvaluatorFlags . ExpectingTypeAnnotation ) === 0 ) { return classType ; } if ( ! typeArgs || typeArgs . length !== 1 ) { addError ( isRequired ? Localizer . Diagnostic . requiredArgCount ( ) : Localizer . Diagnostic . notRequiredArgCount ( ) , errorNode ) ; return classType ; } const typeArgType = typeArgs [ 0 ] . type ; const containingClassNode = ParseTreeUtils . getEnclosingClass ( errorNode , true ) ; const classTypeInfo = containingClassNode ? getTypeOfClass ( containingClassNode ) : undefined ; let isUsageLegal = false ; if ( classTypeInfo && isInstantiableClass ( classTypeInfo . classType ) && ClassType . isTypedDictClass ( classTypeInfo . classType ) ) { if ( errorNode . parent ?. nodeType === ParseNodeType . TypeAnnotation && errorNode . parent . typeAnnotation === errorNode ) { isUsageLegal = true ; } } if ( ( flags & EvaluatorFlags . RequiredAllowed ) !== 0 ) { isUsageLegal = true ; } if ( ! isUsageLegal ) { addError ( isRequired ? Localizer . Diagnostic . requiredNotInTypedDict ( ) : Localizer . Diagnostic . notRequiredNotInTypedDict ( ) , errorNode ) ; return ClassType . cloneForSpecialization ( classType , [ convertToInstance ( typeArgType ) ] , ! ! typeArgs ) ; } return typeArgType ; } function createUnpackType ( errorNode , typeArgs ) { if ( ! typeArgs || typeArgs . length !== 1 ) { addError ( Localizer . Diagnostic . unpackArgCount ( ) , errorNode ) ; return UnknownType . create ( ) ; } let typeArgType = typeArgs [ 0 ] . type ; if ( isUnion ( typeArgType ) && typeArgType . subtypes . length === 1 ) { typeArgType = typeArgType . subtypes [ 0 ] ; } if ( ! isVariadicTypeVar ( typeArgType ) || typeArgType . isVariadicUnpacked ) { addError ( Localizer . Diagnostic . unpackExpectedTypeVarTuple ( ) , errorNode ) ; return UnknownType . create ( ) ; } return TypeVarType . cloneForUnpacked ( typeArgType ) ; } function createFinalType ( classType , errorNode , typeArgs , flags ) { if ( flags & EvaluatorFlags . FinalDisallowed ) { addError ( Localizer . Diagnostic . finalContext ( ) , errorNode ) ; return AnyType . create ( ) ; } if ( ! typeArgs || typeArgs . length === 0 ) { return classType ; } if ( typeArgs . length > 1 ) { addError ( Localizer . Diagnostic . finalTooManyArgs ( ) , errorNode ) ; } return typeArgs [ 0 ] . type ; } function createConcatenateType ( errorNode , classType , typeArgs ) { if ( ! typeArgs || typeArgs . length === 0 ) { addError ( Localizer . Diagnostic . concatenateTypeArgsMissing ( ) , errorNode ) ; } else { typeArgs . forEach ( ( typeArg , index ) => { if ( index === typeArgs . length - 1 ) { if ( ! isParamSpec ( typeArg . type ) ) { addError ( Localizer . Diagnostic . concatenateParamSpecMissing ( ) , typeArg . node ) ; } } else { if ( isParamSpec ( typeArg . type ) ) { addError ( Localizer . Diagnostic . paramSpecContext ( ) , typeArg . node ) ; } } } ) ; } return createSpecialType ( classType , typeArgs , undefined , true ) ; } function createAnnotatedType ( errorNode , typeArgs ) { if ( typeArgs && typeArgs . length < 2 ) { addError ( Localizer . Diagnostic . annotatedTypeArgMissing ( ) , errorNode ) ; } if ( ! typeArgs || typeArgs . length === 0 ) { return AnyType . create ( ) ; } let typeArg0Type = typeArgs [ 0 ] . type ; if ( ! validateTypeArg ( typeArgs [ 0 ] ) ) { typeArg0Type = UnknownType . create ( ) ; } return TypeBase . cloneForAnnotated ( typeArg0Type ) ; } function createSpecialType ( classType , typeArgs , paramLimit ? , allowParamSpec = false , isCallable = false ) { const isTupleTypeParam = ClassType . isTupleClass ( classType ) ; if ( typeArgs ) { if ( isTupleTypeParam && typeArgs . length === 1 && typeArgs [ 0 ] . isEmptyTupleShorthand ) { typeArgs = [ ] ; } else { let sawVariadic = false ; let reportedVariadicError = false ; typeArgs . forEach ( ( typeArg , index ) => { if ( isEllipsisType ( typeArg . type ) ) { if ( ! isTupleTypeParam ) { addError ( Localizer . Diagnostic . ellipsisContext ( ) , typeArg . node ) ; } else if ( typeArgs ! . length !== 2 || index !== 1 ) { addError ( Localizer . Diagnostic . ellipsisSecondArg ( ) , typeArg . node ) ; } else { if ( isTypeVar ( typeArgs ! [ 0 ] . type ) && isVariadicTypeVar ( typeArgs ! [ 0 ] . type ) && ! typeArgs ! [ 0 ] . type . isVariadicInUnion ) { addError ( Localizer . Diagnostic . typeVarTupleContext ( ) , typeArgs ! [ 0 ] . node ) ; } } } else if ( isParamSpec ( typeArg . type ) && allowParamSpec ) { } else if ( isVariadicTypeVar ( typeArg . type ) && paramLimit === undefined ) { if ( sawVariadic ) { if ( ! reportedVariadicError ) { addError ( Localizer . Diagnostic . variadicTypeArgsTooMany ( ) , typeArg . node ) ; reportedVariadicError = true ; } } validateVariadicTypeVarIsUnpacked ( typeArg . type , typeArg . node ) ; sawVariadic = true ; } else { validateTypeArg ( typeArg ) ; } } ) ; } } let typeArgTypes = typeArgs ? typeArgs . map ( ( t ) => convertToInstance ( t . type ) ) : [ ] ; if ( paramLimit !== undefined ) { if ( typeArgs && typeArgTypes . length > paramLimit ) { addError ( Localizer . Diagnostic . typeArgsTooMany ( ) . format ( { name : classType . aliasName || classType . details . name , expected : paramLimit , received : typeArgTypes . length , } ) , typeArgs [ paramLimit ] . node ) ; typeArgTypes = typeArgTypes . slice ( 0 , paramLimit ) ; } else if ( typeArgTypes . length < paramLimit ) { while ( typeArgTypes . length < paramLimit ) { typeArgTypes . push ( UnknownType . create ( ) ) ; } } } let returnType ; if ( isTupleTypeParam ) { if ( ! typeArgs ) { typeArgTypes . push ( UnknownType . create ( ) ) ; typeArgTypes . push ( AnyType . create ( true ) ) ; } returnType = specializeTupleClass ( classType , typeArgTypes , typeArgs !== undefined , false ) ; } else { returnType = ClassType . cloneForSpecialization ( classType , typeArgTypes , typeArgs !== undefined ) ; } if ( ! isCallable ) { TypeBase . setSpecialForm ( returnType ) ; } return returnType ; } function createUnionType ( classType , errorNode , typeArgs , flags ) { const types = [ ] ; if ( ! typeArgs ) { if ( ( flags & EvaluatorFlags . ExpectingTypeAnnotation ) !== 0 ) { addError ( Localizer . Diagnostic . unionTypeArgCount ( ) , errorNode ) ; return NeverType . create ( ) ; } return classType ; } for ( const typeArg of typeArgs ) { let typeArgType = typeArg . type ; if ( ! validateTypeArg ( typeArg , false , true ) ) { typeArgType = UnknownType . create ( ) ; } else if ( ! TypeBase . isInstantiable ( typeArgType ) ) { addExpectedClassDiagnostic ( typeArgType , typeArg . node ) ; typeArgType = UnknownType . create ( ) ; } if ( isTypeVar ( typeArgType ) && isVariadicTypeVar ( typeArgType ) && typeArgType . isVariadicUnpacked ) { typeArgType = TypeVarType . cloneForUnpacked ( typeArgType , true ) ; } types . push ( typeArgType ) ; } if ( types . length === 1 ) { if ( ! isVariadicTypeVar ( types [ 0 ] ) && ! isNoneInstance ( types [ 0 ] ) ) { addError ( Localizer . Diagnostic . unionTypeArgCount ( ) , errorNode ) ; } } const unionType = combineTypes ( types ) ; if ( isUnion ( unionType ) ) { TypeBase . setSpecialForm ( unionType ) ; } return unionType ; } function createGenericType ( classType , errorNode , typeArgs , flags ) { if ( ! typeArgs ) { if ( ( flags & ( EvaluatorFlags . ExpectingTypeAnnotation | EvaluatorFlags . DisallowNakedGeneric ) ) !== 0 ) { addError ( Localizer . Diagnostic . genericTypeArgMissing ( ) , errorNode ) ; } return classType ; } const uniqueTypeVars = [ ] ; if ( typeArgs ) { if ( typeArgs . length === 0 ) { addError ( Localizer . Diagnostic . genericTypeArgMissing ( ) , errorNode ) ; } typeArgs . forEach ( ( typeArg ) => { if ( ! isTypeVar ( typeArg . type ) ) { addError ( Localizer . Diagnostic . genericTypeArgTypeVar ( ) , typeArg . node ) ; } else { if ( uniqueTypeVars . some ( ( t ) => isTypeSame ( t , typeArg . type ) ) ) { addError ( Localizer . Diagnostic . genericTypeArgUnique ( ) , typeArg . node ) ; } uniqueTypeVars . push ( typeArg . type ) ; } } ) ; } return createSpecialType ( classType , typeArgs , undefined , true ) ; } function transformTypeForPossibleEnumClass ( node , getValueType ) { const enclosingClassNode = ParseTreeUtils . getEnclosingClass ( node , true ) ; if ( enclosingClassNode ) { const enumClassInfo = getTypeOfClass ( enclosingClassNode ) ; if ( enumClassInfo && ClassType . isEnumClass ( enumClassInfo . classType ) ) { let isMemberOfEnumeration = ( node . parent ?. nodeType === ParseNodeType . Assignment && node . parent . leftExpression === node ) || ( node . parent ?. nodeType === ParseNodeType . TypeAnnotation && node . parent . valueExpression === node && node . parent . parent ?. nodeType === ParseNodeType . Assignment ) || ( AnalyzerNodeInfo . getFileInfo ( node ) . isStubFile && node . parent ?. nodeType === ParseNodeType . TypeAnnotation && node . parent . valueExpression === node ) ; if ( isSingleDunderName ( node . value ) ) { isMemberOfEnumeration = false ; } if ( node . value === 'name' || node . value === 'value' ) { isMemberOfEnumeration = false ; } const valueType = getValueType ( ) ; if ( isClassInstance ( valueType ) && valueType . details . fields . get ( '__get__' ) ) { isMemberOfEnumeration = false ; } if ( isMemberOfEnumeration ) { return ClassType . cloneAsInstance ( ClassType . cloneWithLiteral ( enumClassInfo . classType , new EnumLiteral ( enumClassInfo . classType . details . name , node . value , valueType ) ) ) ; } } } return undefined ; } function transformTypeForTypeAlias ( type , name , errorNode ) { if ( ! TypeBase . isInstantiable ( type ) ) { return type ; } if ( isTypeAliasPlaceholder ( type ) ) { return type ; } let typeParameters = [ ] ; if ( ! isTypeVar ( type ) || TypeBase . isAnnotated ( type ) ) { doForEachSubtype ( type , ( subtype ) => { addTypeVarsToListIfUnique ( typeParameters , getTypeVarArgumentsRecursive ( subtype ) ) ; } ) ; } typeParameters = typeParameters . filter ( ( typeVar ) => ! typeVar . details . isSynthesized ) ; typeParameters = typeParameters . map ( ( typeVar ) => { if ( TypeBase . isInstance ( typeVar ) ) { return typeVar ; } return convertToInstance ( typeVar ) as TypeVarType ; } ) ; const variadics = typeParameters . filter ( ( param ) => isVariadicTypeVar ( param ) ) ; if ( variadics . length > 1 ) { addError ( Localizer . Diagnostic . variadicTypeParamTooManyAlias ( ) . format ( { names : variadics . map ( ( v ) => `"${ v . details . name }"` ) . join ( ', ' ) , } ) , errorNode ) ; } const fileInfo = AnalyzerNodeInfo . getFileInfo ( name ) ; const typeAliasScopeId = getScopeIdForNode ( name ) ; const boundTypeVars = typeParameters . filter ( ( typeVar ) => typeVar . scopeId !== typeAliasScopeId && typeVar . scopeType === TypeVarScopeType . Class ) ; if ( boundTypeVars . length > 0 ) { addError ( Localizer . Diagnostic . genericTypeAliasBoundTypeVar ( ) . format ( { names : boundTypeVars . map ( ( t ) => `${ t . details . name }` ) . join ( ', ' ) , } ) , errorNode ) ; } return TypeBase . cloneForTypeAlias ( type , name . value , `${ fileInfo . moduleName }.${ name . value }` , typeAliasScopeId , typeParameters . length > 0 ? typeParameters : undefined ) ; } function createSpecialBuiltInClass ( node , assignedName , aliasMapEntry ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; let specialClassType = ClassType . createInstantiable ( assignedName , ParseTreeUtils . getClassFullName ( node , fileInfo . moduleName , assignedName ) , fileInfo . moduleName , fileInfo . filePath , ClassTypeFlags . BuiltInClass | ClassTypeFlags . SpecialBuiltIn , 0 , undefined , undefined ) ; if ( fileInfo . isTypingExtensionsStubFile ) { specialClassType . details . flags |= ClassTypeFlags . TypingExtensionClass ; } const baseClassName = aliasMapEntry . alias || 'object' ; let baseClass ; if ( aliasMapEntry . module === 'builtins' ) { baseClass = getBuiltInType ( node , baseClassName ) ; } else if ( aliasMapEntry . module === 'collections' ) { if ( fileInfo . collectionsModulePath ) { const lookupResult = importLookup ( fileInfo . collectionsModulePath ) ; if ( lookupResult ) { const symbol = lookupResult . symbolTable . get ( baseClassName ) ; if ( symbol ) { baseClass = getEffectiveTypeOfSymbol ( symbol ) ; } } } } else if ( aliasMapEntry . module === 'self' ) { const symbolWithScope = lookUpSymbolRecursive ( node , baseClassName , false ) ; if ( symbolWithScope ) { baseClass = getEffectiveTypeOfSymbol ( symbolWithScope . symbol ) ; if ( isInstantiableClass ( baseClass ) && ClassType . isBuiltIn ( baseClass , '_TypedDict' ) ) { baseClass . details . flags &= ~ ClassTypeFlags . SupportsAbstractMethods ; } } } if ( baseClass && isInstantiableClass ( baseClass ) ) { if ( aliasMapEntry . alias ) { specialClassType = ClassType . cloneForTypingAlias ( baseClass , assignedName ) ; } else { specialClassType . details . baseClasses . push ( baseClass ) ; specialClassType . details . effectiveMetaclass = baseClass . details . effectiveMetaclass ; computeMroLinearization ( specialClassType ) ; } } else { specialClassType . details . baseClasses . push ( UnknownType . create ( ) ) ; specialClassType . details . effectiveMetaclass = UnknownType . create ( ) ; computeMroLinearization ( specialClassType ) ; } return specialClassType ; } function handleTypingStubTypeAnnotation ( node ) { if ( ! node . parent || node . parent . nodeType !== ParseNodeType . TypeAnnotation ) { return undefined ; } if ( node . parent . valueExpression . nodeType !== ParseNodeType . Name ) { return undefined ; } const nameNode = node . parent . valueExpression ; const assignedName = nameNode . value ; const specialTypes = new Map ( [ [ 'Tuple' , { alias : 'tuple' , module : 'builtins' } ] , [ 'Generic' , { alias : '' , module : 'builtins' } ] , [ 'Protocol' , { alias : '' , module : 'builtins' } ] , [ 'Callable' , { alias : '' , module : 'builtins' } ] , [ 'Type' , { alias : 'type' , module : 'builtins' } ] , [ 'ClassVar' , { alias : '' , module : 'builtins' } ] , [ 'Final' , { alias : '' , module : 'builtins' } ] , [ 'Literal' , { alias : '' , module : 'builtins' } ] , [ 'TypedDict' , { alias : '_TypedDict' , module : 'self' } ] , [ 'Union' , { alias : '' , module : 'builtins' } ] , [ 'Optional' , { alias : '' , module : 'builtins' } ] , [ 'Annotated' , { alias : '' , module : 'builtins' } ] , [ 'TypeAlias' , { alias : '' , module : 'builtins' } ] , [ 'Concatenate' , { alias : '' , module : 'builtins' } ] , [ 'TypeGuard' , { alias : '' , module : 'builtins' } ] , [ 'Unpack' , { alias : '' , module : 'builtins' } ] , [ 'Required' , { alias : '' , module : 'builtins' } ] , [ 'NotRequired' , { alias : '' , module : 'builtins' } ] , [ 'Self' , { alias : '' , module : 'builtins' } ] , [ 'NoReturn' , { alias : '' , module : 'builtins' } ] , ] ) ; const aliasMapEntry = specialTypes . get ( assignedName ) ; if ( aliasMapEntry ) { const cachedType = readTypeCache ( node , EvaluatorFlags . None ) ; if ( cachedType ) { assert ( isInstantiableClass ( cachedType ) ) ; return cachedType as ClassType ; } const specialType = createSpecialBuiltInClass ( node , assignedName , aliasMapEntry ) ; writeTypeCache ( node , specialType , EvaluatorFlags . None , false ) ; return specialType ; } return undefined ; } function handleTypingStubAssignment ( node ) { if ( node . leftExpression . nodeType !== ParseNodeType . Name ) { return undefined ; } const nameNode = node . leftExpression ; const assignedName = nameNode . value ; if ( assignedName === 'Any' ) { return AnyType . create ( ) ; } const specialTypes = new Map ( [ [ 'overload' , { alias : '' , module : 'builtins' } ] , [ 'TypeVar' , { alias : '' , module : 'builtins' } ] , [ '_promote' , { alias : '' , module : 'builtins' } ] , [ 'no_type_check' , { alias : '' , module : 'builtins' } ] , [ 'NoReturn' , { alias : '' , module : 'builtins' } ] , [ 'Counter' , { alias : 'Counter' , module : 'collections' } ] , [ 'List' , { alias : 'list' , module : 'builtins' } ] , [ 'Dict' , { alias : 'dict' , module : 'builtins' } ] , [ 'DefaultDict' , { alias : 'defaultdict' , module : 'collections' } ] , [ 'Set' , { alias : 'set' , module : 'builtins' } ] , [ 'FrozenSet' , { alias : 'frozenset' , module : 'builtins' } ] , [ 'Deque' , { alias : 'deque' , module : 'collections' } ] , [ 'ChainMap' , { alias : 'ChainMap' , module : 'collections' } ] , [ 'OrderedDict' , { alias : 'OrderedDict' , module : 'collections' } ] , ] ) ; const aliasMapEntry = specialTypes . get ( assignedName ) ; if ( aliasMapEntry ) { getTypeOfExpression ( node . rightExpression ) ; return createSpecialBuiltInClass ( node , assignedName , aliasMapEntry ) ; } return undefined ; } function evaluateTypesForAssignmentStatement ( node ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; if ( readTypeCache ( node , EvaluatorFlags . None ) ) { return ; } let rightHandType = readTypeCache ( node . rightExpression , EvaluatorFlags . None ) ; let isIncomplete = false ; let expectedTypeDiagAddendum ; if ( ! rightHandType ) { if ( fileInfo . isTypingStubFile || fileInfo . isTypingExtensionsStubFile ) { rightHandType = handleTypingStubAssignment ( node ) ; if ( rightHandType ) { writeTypeCache ( node . rightExpression , rightHandType , EvaluatorFlags . None , false ) ; } } if ( ! rightHandType ) { const declaredType = getDeclaredTypeForExpression ( node . leftExpression , { method : 'set' } ) ; let flags = EvaluatorFlags . None ; if ( fileInfo . isStubFile ) { flags |= EvaluatorFlags . ConvertEllipsisToUnknown ; } if ( node . rightExpression . nodeType === ParseNodeType . Name ) { flags |= EvaluatorFlags . DoNotSpecialize ; } let typeAliasNameNode ; let isSpeculativeTypeAlias = false ; if ( isDeclaredTypeAlias ( node . leftExpression ) ) { flags |= EvaluatorFlags . ExpectingType | EvaluatorFlags . EvaluateStringLiteralAsType | EvaluatorFlags . ParamSpecDisallowed | EvaluatorFlags . TypeVarTupleDisallowed ; flags &= ~ EvaluatorFlags . DoNotSpecialize ; typeAliasNameNode = ( node . leftExpression as TypeAnnotationNode ) . valueExpression as NameNode ; } else if ( node . leftExpression . nodeType === ParseNodeType . Name ) { const symbolWithScope = lookUpSymbolRecursive ( node . leftExpression , node . leftExpression . value , false ) ; if ( symbolWithScope ) { const decls = symbolWithScope . symbol . getDeclarations ( ) ; if ( decls . length === 1 && isPossibleTypeAliasDeclaration ( decls [ 0 ] ) ) { typeAliasNameNode = node . leftExpression ; isSpeculativeTypeAlias = true ; } } } let typeAliasTypeVar ; if ( typeAliasNameNode ) { typeAliasTypeVar = TypeVarType . createInstantiable ( `__type_alias_${ typeAliasNameNode . value }` ) ; typeAliasTypeVar . details . isSynthesized = true ; typeAliasTypeVar . details . recursiveTypeAliasName = typeAliasNameNode . value ; const scopeId = getScopeIdForNode ( typeAliasNameNode ) ; typeAliasTypeVar . details . recursiveTypeAliasScopeId = scopeId ; typeAliasTypeVar . scopeId = scopeId ; writeTypeCache ( node , typeAliasTypeVar , undefined , false ) ; writeTypeCache ( node . leftExpression , typeAliasTypeVar , undefined , false ) ; if ( node . leftExpression . nodeType === ParseNodeType . TypeAnnotation ) { writeTypeCache ( node . leftExpression . valueExpression , typeAliasTypeVar , undefined , false ) ; } } const srcTypeResult = getTypeOfExpression ( node . rightExpression , declaredType , flags ) ; let srcType = srcTypeResult . type ; expectedTypeDiagAddendum = srcTypeResult . expectedTypeDiagAddendum ; if ( srcTypeResult . isIncomplete ) { isIncomplete = true ; } const constExprValue = evaluateStaticBoolExpression ( node . rightExpression , fileInfo . executionEnvironment ) ; if ( constExprValue !== undefined ) { const boolType = getBuiltInObject ( node , 'bool' ) ; if ( isClassInstance ( boolType ) ) { srcType = ClassType . cloneWithLiteral ( boolType , constExprValue ) ; } } if ( declaredType ) { if ( canAssignType ( declaredType , srcType ) ) { if ( ! isAnyOrUnknown ( srcType ) ) { srcType = narrowTypeBasedOnAssignment ( declaredType , srcType ) ; } } } rightHandType = srcType ; if ( node . leftExpression . nodeType === ParseNodeType . Name && ! node . typeAnnotationComment ) { rightHandType = transformTypeForPossibleEnumClass ( node . leftExpression , ( ) => rightHandType ! ) || rightHandType ; } if ( typeAliasNameNode ) { deleteTypeCacheEntry ( node ) ; deleteTypeCacheEntry ( node . leftExpression ) ; if ( node . leftExpression . nodeType === ParseNodeType . TypeAnnotation ) { deleteTypeCacheEntry ( node . leftExpression . valueExpression ) ; } if ( ! isSpeculativeTypeAlias || ( TypeBase . isInstantiable ( rightHandType ) && ! isUnknown ( rightHandType ) ) ) { rightHandType = transformTypeForTypeAlias ( rightHandType , typeAliasNameNode , node . rightExpression ) ; if ( isTypeAliasRecursive ( typeAliasTypeVar ! , rightHandType ) ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeAliasIsRecursiveDirect ( ) . format ( { name : typeAliasNameNode . value , } ) , node . rightExpression ) ; } typeAliasTypeVar ! . details . boundType = rightHandType ; typeAliasTypeVar ! . details . recursiveTypeParameters = rightHandType . typeAliasInfo ?. typeParameters ; } if ( typeAliasTypeVar ! . details . illegalRecursionDetected ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeAliasIsRecursiveIndirect ( ) . format ( { name : typeAliasNameNode . value , } ) , node . leftExpression ) ; } } } } assignTypeToExpression ( node . leftExpression , rightHandType , isIncomplete , node . rightExpression , true , expectedTypeDiagAddendum ) ; writeTypeCache ( node , rightHandType , EvaluatorFlags . None , isIncomplete ) ; } function evaluateTypesForAugmentedAssignment ( node ) { if ( readTypeCache ( node , EvaluatorFlags . None ) ) { return ; } const destTypeResult = getTypeFromAugmentedAssignment ( node , undefined ) ; assignTypeToExpression ( node . destExpression , destTypeResult . type , ! ! destTypeResult . isIncomplete , node . rightExpression ) ; writeTypeCache ( node , destTypeResult . type , EvaluatorFlags . None , ! ! destTypeResult . isIncomplete ) ; } function getTypeOfClass ( node ) { const cachedClassType = readTypeCache ( node . name , EvaluatorFlags . None ) ; if ( cachedClassType ) { if ( ! isInstantiableClass ( cachedClassType ) ) { return undefined ; } return { classType : cachedClassType , decoratedType : readTypeCache ( node , EvaluatorFlags . None ) || UnknownType . create ( ) , } ; } const scope = ScopeUtils . getScopeForNode ( node ) ; const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; let classFlags = ClassTypeFlags . None ; if ( scope ?. type === ScopeType . Builtin || fileInfo . isTypingStubFile || fileInfo . isTypingExtensionsStubFile || fileInfo . isBuiltInStubFile ) { classFlags |= ClassTypeFlags . BuiltInClass ; if ( fileInfo . isTypingExtensionsStubFile ) { classFlags |= ClassTypeFlags . TypingExtensionClass ; } if ( node . name . value === 'property' ) { classFlags |= ClassTypeFlags . PropertyClass ; } if ( node . name . value === 'tuple' ) { classFlags |= ClassTypeFlags . TupleClass ; } } if ( fileInfo . isStubFile ) { classFlags |= ClassTypeFlags . DefinedInStub ; } const classType = ClassType . createInstantiable ( node . name . value , ParseTreeUtils . getClassFullName ( node , fileInfo . moduleName , node . name . value ) , fileInfo . moduleName , fileInfo . filePath , classFlags , 0 , undefined , undefined , ParseTreeUtils . getDocString ( node . suite . statements ) ) ; classType . details . typeVarScopeId = getScopeIdForNode ( node ) ; const classSymbol = scope ?. lookUpSymbol ( node . name . value ) ; let classDecl ; const decl = AnalyzerNodeInfo . getDeclaration ( node ) ; if ( decl ) { classDecl = decl as ClassDeclaration ; } if ( classDecl && classSymbol ) { setSymbolResolutionPartialType ( classSymbol , classDecl , classType ) ; } classType . details . flags |= ClassTypeFlags . PartiallyConstructed ; writeTypeCache ( node , classType , undefined , false ) ; writeTypeCache ( node . name , classType , undefined , false ) ; const typeParameters = [ ] ; let genericTypeParameters ; const initSubclassArgs = [ ] ; let metaclassNode ; let exprFlags = EvaluatorFlags . ExpectingType | EvaluatorFlags . AllowGenericClassType | EvaluatorFlags . DisallowNakedGeneric | EvaluatorFlags . DisallowTypeVarsWithScopeId | EvaluatorFlags . AssociateTypeVarsWithCurrentScope ; if ( fileInfo . isStubFile ) { exprFlags |= EvaluatorFlags . AllowForwardReferences ; } node . arguments . forEach ( ( arg ) => { if ( ! arg . name ) { let argType = getTypeOfExpression ( arg . valueExpression , undefined , exprFlags ) . type ; if ( isUnion ( argType ) ) { argType = removeUnbound ( argType ) ; } if ( ! isAnyOrUnknown ( argType ) && ! isUnbound ( argType ) ) { if ( ! isInstantiableClass ( argType ) ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . baseClassInvalid ( ) , arg ) ; argType = UnknownType . create ( ) ; } else { if ( ClassType . isBuiltIn ( argType , 'Protocol' ) ) { if ( ! fileInfo . isStubFile && ! ClassType . isTypingExtensionClass ( argType ) && fileInfo . executionEnvironment . pythonVersion < PythonVersion . V3_7 ) { addError ( Localizer . Diagnostic . protocolIllegal ( ) , arg . valueExpression ) ; } classType . details . flags |= ClassTypeFlags . ProtocolClass ; } if ( ClassType . isBuiltIn ( argType , 'property' ) ) { classType . details . flags |= ClassTypeFlags . PropertyClass ; } if ( fileInfo . executionEnvironment . pythonVersion >= PythonVersion . V3_6 ) { if ( ClassType . isBuiltIn ( argType , 'NamedTuple' ) ) { classType . details . flags |= ClassTypeFlags . DataClass | ClassTypeFlags . ReadOnlyInstanceVariables ; } } if ( ClassType . isBuiltIn ( argType , 'TypedDict' ) || ClassType . isTypedDictClass ( argType ) ) { classType . details . flags |= ClassTypeFlags . TypedDictClass ; } else if ( ClassType . isTypedDictClass ( classType ) && ! ClassType . isTypedDictClass ( argType ) ) { addError ( Localizer . Diagnostic . typedDictBaseClass ( ) , arg ) ; } if ( derivesFromClassRecursive ( argType , classType , true ) ) { addError ( Localizer . Diagnostic . baseClassCircular ( ) , arg ) ; argType = UnknownType . create ( ) ; } } } if ( isUnknown ( argType ) ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportUntypedBaseClass , DiagnosticRule . reportUntypedBaseClass , Localizer . Diagnostic . baseClassUnknown ( ) , arg ) ; } if ( classType . details . baseClasses . some ( ( prevBaseClass ) => { return ( isInstantiableClass ( prevBaseClass ) && isInstantiableClass ( argType ) && ClassType . isSameGenericClass ( argType , prevBaseClass ) ) ; } ) ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . duplicateBaseClass ( ) , arg . name || arg ) ; } classType . details . baseClasses . push ( argType ) ; if ( isInstantiableClass ( argType ) ) { if ( ClassType . isEnumClass ( argType ) ) { classType . details . flags |= ClassTypeFlags . EnumClass ; } if ( ClassType . supportsAbstractMethods ( argType ) || ( ClassType . isProtocolClass ( argType ) && ! ClassType . isBuiltIn ( argType ) ) ) { classType . details . flags |= ClassTypeFlags . SupportsAbstractMethods ; } if ( ClassType . isPropertyClass ( argType ) ) { classType . details . flags |= ClassTypeFlags . PropertyClass ; } if ( ClassType . isFinal ( argType ) ) { const className = printObjectTypeForClass ( argType ) ; addError ( Localizer . Diagnostic . baseClassFinal ( ) . format ( { type : className } ) , arg . valueExpression ) ; } } addTypeVarsToListIfUnique ( typeParameters , getTypeVarArgumentsRecursive ( argType ) ) ; if ( isInstantiableClass ( argType ) && ClassType . isBuiltIn ( argType , 'Generic' ) ) { if ( ! genericTypeParameters ) { genericTypeParameters = [ ] ; addTypeVarsToListIfUnique ( genericTypeParameters , getTypeVarArgumentsRecursive ( argType ) ) ; } } } else if ( arg . name . value === 'metaclass' ) { if ( metaclassNode ) { addError ( Localizer . Diagnostic . metaclassDuplicate ( ) , arg ) ; } else { metaclassNode = arg . valueExpression ; } } else if ( arg . name . value === 'total' && ClassType . isTypedDictClass ( classType ) ) { const constArgValue = evaluateStaticBoolExpression ( arg . valueExpression , fileInfo . executionEnvironment ) ; if ( constArgValue === undefined ) { addError ( Localizer . Diagnostic . typedDictTotalParam ( ) , arg . valueExpression ) ; } else if ( ! constArgValue ) { classType . details . flags |= ClassTypeFlags . CanOmitDictValues ; } } else { initSubclassArgs . push ( { argumentCategory : ArgumentCategory . Simple , node : arg , name : arg . name , valueExpression : arg . valueExpression , } ) ; } } ) ; if ( classType . details . baseClasses . length > 1 ) { if ( classType . details . baseClasses . some ( ( baseClass ) => isInstantiableClass ( baseClass ) && ClassType . isBuiltIn ( baseClass , 'NamedTuple' ) ) ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . namedTupleMultipleInheritance ( ) , node . name ) ; } } if ( ! ClassType . isBuiltIn ( classType , 'object' ) ) { classType . details . baseClasses . push ( getBuiltInType ( node , 'object' ) ) ; } if ( genericTypeParameters ) { verifyGenericTypeParameters ( node . name , typeParameters , genericTypeParameters ) ; } classType . details . typeParameters = genericTypeParameters || typeParameters ; const variadics = classType . details . typeParameters . filter ( ( param ) => isVariadicTypeVar ( param ) ) ; if ( variadics . length > 1 ) { addError ( Localizer . Diagnostic . variadicTypeParamTooManyClass ( ) . format ( { names : variadics . map ( ( v ) => `"${ v . details . name }"` ) . join ( ', ' ) , } ) , node . name , TextRange . combine ( node . arguments ) || node . name ) ; } if ( ! computeMroLinearization ( classType ) ) { addError ( Localizer . Diagnostic . methodOrdering ( ) , node . name ) ; } const innerScope = ScopeUtils . getScopeForNode ( node . suite ) ; classType . details . fields = innerScope ?. symbolTable || new Map < string , Symbol > ( ) ; const slotsNames = innerScope ?. getSlotsNames ( ) ; if ( slotsNames ) { classType . details . localSlotsNames = slotsNames ; } if ( ClassType . isTypedDictClass ( classType ) ) { synthesizeTypedDictClassMethods ( evaluatorInterface , node , classType ) ; } if ( ! fileInfo . isStubFile && classType . details . typeParameters . length === 0 ) { const initMethod = classType . details . fields . get ( '__init__' ) ; if ( initMethod ) { const initDecls = initMethod . getTypedDeclarations ( ) ; if ( initDecls . length === 1 && initDecls [ 0 ] . type === DeclarationType . Function ) { const initDeclNode = initDecls [ 0 ] . node ; const initParams = initDeclNode . parameters ; if ( initParams . length > 1 && ! initParams . some ( ( param , index ) => ! ! getTypeAnnotationForParameter ( initDeclNode , index ) ) ) { const genericParams = initParams . filter ( ( param , index ) => index > 0 && param . name && param . category === ParameterCategory . Simple ) ; if ( genericParams . length > 0 ) { classType . details . flags |= ClassTypeFlags . PseudoGenericClass ; classType . details . typeParameters = genericParams . map ( ( param ) => { const typeVar = TypeVarType . createInstance ( `__type_of_${ param . name ! . value }` ) ; typeVar . details . isSynthesized = true ; typeVar . scopeId = getScopeIdForNode ( initDeclNode ) ; typeVar . details . boundType = UnknownType . create ( ) ; return TypeVarType . cloneForScopeId ( typeVar , getScopeIdForNode ( node ) , node . name . value , TypeVarScopeType . Class ) ; } ) ; } } } } } if ( classType . details . typeParameters . length === 0 && ! ClassType . isBuiltIn ( classType , 'type' ) ) { if ( classType . details . baseClasses . some ( ( baseClass ) => isInstantiableClass ( baseClass ) && ClassType . hasCustomClassGetItem ( baseClass ) ) || classType . details . fields . has ( '__class_getitem__' ) ) { classType . details . flags |= ClassTypeFlags . HasCustomClassGetItem ; } } if ( metaclassNode ) { const metaclassType = getTypeOfExpression ( metaclassNode , undefined , exprFlags ) . type ; if ( isInstantiableClass ( metaclassType ) || isUnknown ( metaclassType ) ) { if ( requiresSpecialization ( metaclassType ) ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . metaclassIsGeneric ( ) , metaclassNode ) ; } classType . details . declaredMetaclass = metaclassType ; if ( isInstantiableClass ( metaclassType ) ) { if ( ClassType . isBuiltIn ( metaclassType , 'EnumMeta' ) ) { classType . details . flags |= ClassTypeFlags . EnumClass ; } else if ( ClassType . isBuiltIn ( metaclassType , 'ABCMeta' ) ) { classType . details . flags |= ClassTypeFlags . SupportsAbstractMethods ; } } } } let effectiveMetaclass = classType . details . declaredMetaclass ; let reportedMetaclassConflict = false ; if ( ! effectiveMetaclass || isInstantiableClass ( effectiveMetaclass ) ) { for ( const baseClass of classType . details . baseClasses ) { if ( isInstantiableClass ( baseClass ) ) { const baseClassMeta = baseClass . details . effectiveMetaclass || typeClassType ; if ( baseClassMeta && isInstantiableClass ( baseClassMeta ) ) { if ( ! effectiveMetaclass ) { effectiveMetaclass = baseClassMeta ; } else if ( derivesFromClassRecursive ( baseClassMeta , effectiveMetaclass , false ) ) { effectiveMetaclass = baseClassMeta ; } else if ( ! derivesFromClassRecursive ( effectiveMetaclass , baseClassMeta , false ) ) { if ( ! reportedMetaclassConflict ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . metaclassConflict ( ) , node . name ) ; reportedMetaclassConflict = true ; } } } else { effectiveMetaclass = baseClassMeta ? UnknownType . create ( ) : undefined ; break ; } } else { effectiveMetaclass = UnknownType . create ( ) ; break ; } } } if ( ! effectiveMetaclass ) { const typeMetaclass = getBuiltInType ( node , 'type' ) ; effectiveMetaclass = typeMetaclass && isInstantiableClass ( typeMetaclass ) ? typeMetaclass : UnknownType . create ( ) ; } classType . details . effectiveMetaclass = effectiveMetaclass ; let decoratedType = classType ; let foundUnknown = false ; for ( let i = node . decorators . length - 1 ; i >= 0 ; i -- ) { const decorator = node . decorators [ i ] ; const newDecoratedType = applyClassDecorator ( decoratedType , classType , decorator ) ; if ( containsUnknown ( newDecoratedType ) ) { if ( ! foundUnknown ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportUntypedClassDecorator , DiagnosticRule . reportUntypedClassDecorator , Localizer . Diagnostic . classDecoratorTypeUnknown ( ) , node . decorators [ i ] . expression ) ; foundUnknown = true ; } } else { decoratedType = newDecoratedType ; } } if ( isInstantiableClass ( effectiveMetaclass ) ) { if ( effectiveMetaclass . details . metaclassDataClassTransform ) { applyDataClassDefaultBehaviors ( classType , effectiveMetaclass . details . metaclassDataClassTransform ) ; applyDataClassMetaclassBehaviorOverrides ( evaluatorInterface , classType , initSubclassArgs ) ; } } classType . details . flags &= ~ ClassTypeFlags . PartiallyConstructed ; if ( ClassType . isDataClass ( classType ) ) { let skipSynthesizedInit = ClassType . isSkipSynthesizedDataClassInit ( classType ) ; if ( ! skipSynthesizedInit ) { const initSymbol = lookUpClassMember ( classType , '__init__' , ClassMemberLookupFlags . SkipBaseClasses ) ; if ( initSymbol ) { const initSymbolType = getTypeOfMember ( initSymbol ) ; if ( isFunction ( initSymbolType ) ) { if ( ! FunctionType . isSynthesizedMethod ( initSymbolType ) ) { skipSynthesizedInit = true ; } } else { skipSynthesizedInit = true ; } } } let skipSynthesizeHash = false ; const hashSymbol = lookUpClassMember ( classType , '__hash__' , ClassMemberLookupFlags . SkipBaseClasses ) ; if ( hashSymbol ) { const hashSymbolType = getTypeOfMember ( hashSymbol ) ; if ( isFunction ( hashSymbolType ) && ! FunctionType . isSynthesizedMethod ( hashSymbolType ) ) { skipSynthesizeHash = true ; } } synthesizeDataClassMethods ( evaluatorInterface , node , classType , skipSynthesizedInit , skipSynthesizeHash ) ; } if ( classType . details . localSlotsNames ) { let isLimitedToSlots = true ; const extendedSlotsNames = [ ... classType . details . localSlotsNames ] ; classType . details . baseClasses . forEach ( ( baseClass ) => { if ( isInstantiableClass ( baseClass ) ) { if ( ! ClassType . isBuiltIn ( baseClass , 'object' ) && ! ClassType . isBuiltIn ( baseClass , 'type' ) && ! ClassType . isBuiltIn ( baseClass , 'Generic' ) ) { if ( baseClass . details . inheritedSlotsNames === undefined ) { isLimitedToSlots = false ; } else { extendedSlotsNames . push ( ... baseClass . details . inheritedSlotsNames ) ; } } } else { isLimitedToSlots = false ; } } ) ; if ( isLimitedToSlots ) { classType . details . inheritedSlotsNames = extendedSlotsNames ; } } writeTypeCache ( node . name , classType , EvaluatorFlags . None , false ) ; writeTypeCache ( node , decoratedType , EvaluatorFlags . None , false ) ; validateInitSubclassArgs ( node , classType , initSubclassArgs ) ; if ( ClassType . isBuiltIn ( classType , 'UnionType' ) ) { unionType = ClassType . cloneAsInstance ( classType ) ; } return { classType , decoratedType } ; } function verifyGenericTypeParameters ( errorNode , typeVars , genericTypeVars ) { const missingFromGeneric = typeVars . filter ( ( typeVar ) => { return ! genericTypeVars . some ( ( genericTypeVar ) => genericTypeVar . details . name === typeVar . details . name ) ; } ) ; if ( missingFromGeneric . length > 0 ) { const diag = new DiagnosticAddendum ( ) ; diag . addMessage ( Localizer . DiagnosticAddendum . typeVarsMissing ( ) . format ( { names : missingFromGeneric . map ( ( typeVar ) => `"${ typeVar . details . name }"` ) . join ( ', ' ) , } ) ) ; addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeVarsNotInGeneric ( ) + diag . getString ( ) , errorNode ) ; } } function applyClassDecorator ( inputClassType , originalClassType , decoratorNode ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( decoratorNode ) ; let flags = fileInfo . isStubFile ? EvaluatorFlags . AllowForwardReferences : EvaluatorFlags . None ; if ( decoratorNode . expression . nodeType !== ParseNodeType . Call ) { flags |= EvaluatorFlags . DoNotSpecialize ; } const decoratorType = getTypeOfExpression ( decoratorNode . expression , undefined , flags ) . type ; if ( decoratorNode . expression . nodeType === ParseNodeType . Call ) { const decoratorCallType = getTypeOfExpression ( decoratorNode . expression . leftExpression , undefined , flags | EvaluatorFlags . DoNotSpecialize ) . type ; if ( isFunction ( decoratorCallType ) ) { if ( decoratorCallType . details . name === '__dataclass_transform__' ) { originalClassType . details . metaclassDataClassTransform = validateDataClassTransformDecorator ( evaluatorInterface , decoratorNode . expression ) ; } } } if ( isOverloadedFunction ( decoratorType ) ) { const dataclassBehaviors = getDataclassDecoratorBehaviors ( decoratorType ) ; if ( dataclassBehaviors ) { applyDataClassDecorator ( evaluatorInterface , originalClassType , dataclassBehaviors , undefined ) ; return inputClassType ; } } else if ( isFunction ( decoratorType ) ) { if ( decoratorType . details . builtInName === 'final' ) { originalClassType . details . flags |= ClassTypeFlags . Final ; return inputClassType ; } else if ( decoratorType . details . builtInName === 'runtime_checkable' ) { originalClassType . details . flags |= ClassTypeFlags . RuntimeCheckable ; } let dataclassBehaviors ; let callNode ; if ( decoratorNode . expression . nodeType === ParseNodeType . Call ) { callNode = decoratorNode . expression ; const decoratorCallType = getTypeOfExpression ( callNode . leftExpression , undefined , flags | EvaluatorFlags . DoNotSpecialize ) . type ; dataclassBehaviors = getDataclassDecoratorBehaviors ( decoratorCallType ) ; } else { const decoratorType = getTypeOfExpression ( decoratorNode . expression , undefined , flags ) . type ; dataclassBehaviors = getDataclassDecoratorBehaviors ( decoratorType ) ; } if ( dataclassBehaviors ) { applyDataClassDecorator ( evaluatorInterface , originalClassType , dataclassBehaviors , callNode ) ; return inputClassType ; } } return getTypeFromDecorator ( decoratorNode , inputClassType ) ; } function validateInitSubclassArgs ( node , classType , argList ) { const errorNode = argList . length > 0 ? argList [ 0 ] . node ! . name ! : node . name ; const initSubclassMethodInfo = getTypeFromClassMemberName ( errorNode , classType , '__init_subclass__' , { method : 'get' } , undefined , MemberAccessFlags . AccessClassMembersOnly | MemberAccessFlags . SkipObjectBaseClass | MemberAccessFlags . SkipOriginalClass , classType ) ; if ( initSubclassMethodInfo ) { const initSubclassMethodType = initSubclassMethodInfo . type ; if ( initSubclassMethodType ) { validateCallArguments ( errorNode , argList , initSubclassMethodType , undefined , false , NoneType . createInstance ( ) ) ; } } else if ( classType . details . effectiveMetaclass && isClass ( classType . details . effectiveMetaclass ) ) { const newMethodMember = lookUpClassMember ( classType . details . effectiveMetaclass , '__new__' , ClassMemberLookupFlags . SkipTypeBaseClass ) ; if ( newMethodMember ) { const newMethodType = getTypeOfMember ( newMethodMember ) ; if ( isFunction ( newMethodType ) ) { const paramListDetails = getParameterListDetails ( newMethodType ) ; if ( paramListDetails . firstKeywordOnlyIndex !== undefined ) { const paramMap = new Map < string , number > ( ) ; for ( let i = paramListDetails . firstKeywordOnlyIndex ; i < paramListDetails . params . length ; i ++ ) { const paramInfo = paramListDetails . params [ i ] ; if ( paramInfo . param . category === ParameterCategory . Simple && paramInfo . param . name ) { paramMap . set ( paramInfo . param . name , i ) ; } } argList . forEach ( ( arg ) => { if ( arg . argumentCategory === ArgumentCategory . Simple && arg . name ) { const paramIndex = paramMap . get ( arg . name . value ) ?? paramListDetails . kwargsIndex ; if ( paramIndex !== undefined ) { const paramInfo = paramListDetails . params [ paramIndex ] ; const argParam = { paramCategory : paramInfo . param . category , paramType : FunctionType . getEffectiveParameterType ( newMethodType , paramInfo . index ) , requiresTypeVarMatching : false , argument : arg , errorNode : arg . valueExpression ?? errorNode , } ; validateArgType ( argParam , new TypeVarMap ( ) , newMethodType . details . name , true , true , undefined ) ; paramMap . delete ( arg . name . value ) ; } else { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . paramNameMissing ( ) . format ( { name : arg . name . value } ) , arg . name ?? errorNode ) ; } } } ) ; const unassignedParams = [ ] ; paramMap . forEach ( ( index , paramName ) => { const paramInfo = paramListDetails . params [ index ] ; if ( ! paramInfo . param . hasDefault ) { unassignedParams . push ( paramName ) ; } } ) ; if ( unassignedParams . length > 0 ) { const missingParamNames = unassignedParams . map ( ( p ) => `"${ p }"` ) . join ( ', ' ) ; addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , unassignedParams . length === 1 ? Localizer . Diagnostic . argMissingForParam ( ) . format ( { name : missingParamNames } ) : Localizer . Diagnostic . argMissingForParams ( ) . format ( { names : missingParamNames } ) , errorNode ) ; } } } } } argList . forEach ( ( arg ) => { if ( arg . valueExpression ) { getTypeOfExpression ( arg . valueExpression ) ; } } ) ; } function getTypeOfFunction ( node ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; const cachedFunctionType = readTypeCache ( node . name , EvaluatorFlags . None ) as FunctionType ; if ( cachedFunctionType ) { if ( ! isFunction ( cachedFunctionType ) ) { return undefined ; } return { functionType : cachedFunctionType , decoratedType : readTypeCache ( node , EvaluatorFlags . None ) || UnknownType . create ( ) , } ; } let functionDecl ; const decl = AnalyzerNodeInfo . getDeclaration ( node ) ; if ( decl ) { functionDecl = decl as FunctionDeclaration ; } const containingClassNode = ParseTreeUtils . getEnclosingClass ( node , true ) ; let containingClassType ; if ( containingClassNode ) { const classInfo = getTypeOfClass ( containingClassNode ) ; if ( ! classInfo ) { return undefined ; } containingClassType = classInfo . classType ; } let functionFlags = getFunctionFlagsFromDecorators ( node , ! ! containingClassNode ) ; if ( functionDecl ?. isGenerator ) { functionFlags |= FunctionTypeFlags . Generator ; } if ( containingClassNode && node . name . value === '__class_getitem__' ) { functionFlags |= FunctionTypeFlags . ClassMethod ; } if ( fileInfo . isStubFile ) { functionFlags |= FunctionTypeFlags . StubDefinition ; } else if ( fileInfo . isInPyTypedPackage && evaluatorOptions . disableInferenceForPyTypedSources ) { functionFlags |= FunctionTypeFlags . PyTypedDefinition ; } if ( node . isAsync ) { functionFlags |= FunctionTypeFlags . Async ; } const functionType = FunctionType . createInstance ( node . name . value , getFunctionFullName ( node , fileInfo . moduleName , node . name . value ) , fileInfo . moduleName , functionFlags , ParseTreeUtils . getDocString ( node . suite . statements ) ) ; functionType . details . typeVarScopeId = getScopeIdForNode ( node ) ; if ( fileInfo . isBuiltInStubFile || fileInfo . isTypingStubFile || fileInfo . isTypingExtensionsStubFile ) { functionType . details . builtInName = node . name . value ; } functionType . details . declaration = functionDecl ; const scope = ScopeUtils . getScopeForNode ( node ) ; const functionSymbol = scope ?. lookUpSymbolRecursive ( node . name . value ) ; if ( functionDecl && functionSymbol ) { setSymbolResolutionPartialType ( functionSymbol . symbol , functionDecl , functionType ) ; } writeTypeCache ( node , functionType , undefined , false ) ; writeTypeCache ( node . name , functionType , undefined , false ) ; const addGenericParamTypes = containingClassType && ClassType . isPseudoGenericClass ( containingClassType ) && node . name . value === '__init__' ; const paramTypes = [ ] ; let typeParamIndex = 0 ; let firstCommentAnnotationIndex = 0 ; if ( containingClassType && ( functionType . details . flags & FunctionTypeFlags . StaticMethod ) === 0 ) { firstCommentAnnotationIndex = 1 ; } if ( node . functionAnnotationComment && ! node . functionAnnotationComment . isParamListEllipsis ) { const expected = node . parameters . length - firstCommentAnnotationIndex ; const received = node . functionAnnotationComment . paramTypeAnnotations . length ; if ( firstCommentAnnotationIndex > 0 && received === node . parameters . length ) { firstCommentAnnotationIndex = 0 ; } else if ( received !== expected ) { addError ( Localizer . Diagnostic . annotatedParamCountMismatch ( ) . format ( { expected , received , } ) , node . functionAnnotationComment ) ; } } const markParamAccessed = ( param ) => { if ( param . name ) { const symbolWithScope = lookUpSymbolRecursive ( param . name , param . name . value , false ) ; if ( symbolWithScope ) { setSymbolAccessed ( fileInfo , symbolWithScope . symbol , param . name ) ; } } } ; node . parameters . forEach ( ( param , index ) => { let paramType ; let annotatedType ; let isNoneWithoutOptional = false ; let paramTypeNode ; if ( param . name ) { if ( index === 0 && containingClassType && ( FunctionType . isClassMethod ( functionType ) || FunctionType . isInstanceMethod ( functionType ) || FunctionType . isConstructorMethod ( functionType ) ) ) { markParamAccessed ( param ) ; } else if ( FunctionType . isAbstractMethod ( functionType ) ) { markParamAccessed ( param ) ; } else if ( containingClassType && ClassType . isProtocolClass ( containingClassType ) ) { markParamAccessed ( param ) ; } } if ( param . typeAnnotation ) { paramTypeNode = param . typeAnnotation ; } else if ( param . typeAnnotationComment ) { paramTypeNode = param . typeAnnotationComment ; } else if ( node . functionAnnotationComment && ! node . functionAnnotationComment . isParamListEllipsis ) { const adjustedIndex = index - firstCommentAnnotationIndex ; if ( adjustedIndex >= 0 && adjustedIndex < node . functionAnnotationComment . paramTypeAnnotations . length ) { paramTypeNode = node . functionAnnotationComment . paramTypeAnnotations [ adjustedIndex ] ; } } if ( paramTypeNode ) { annotatedType = getTypeOfAnnotation ( paramTypeNode , { associateTypeVarsWithScope : true , allowTypeVarTuple : param . category === ParameterCategory . VarArgList , disallowRecursiveTypeAlias : true , } ) ; if ( isVariadicTypeVar ( annotatedType ) && ! annotatedType . isVariadicUnpacked ) { addError ( Localizer . Diagnostic . unpackedTypeVarTupleExpected ( ) . format ( { name1 : annotatedType . details . name , name2 : annotatedType . details . name , } ) , paramTypeNode ) ; annotatedType = UnknownType . create ( ) ; } } if ( ! annotatedType && addGenericParamTypes ) { if ( index > 0 && param . category === ParameterCategory . Simple && param . name ) { annotatedType = containingClassType ! . details . typeParameters [ typeParamIndex ] ; typeParamIndex ++ ; } } if ( annotatedType ) { const adjustedAnnotatedType = adjustParameterAnnotatedType ( param , annotatedType ) ; if ( adjustedAnnotatedType !== annotatedType ) { annotatedType = adjustedAnnotatedType ; isNoneWithoutOptional = true ; } } let defaultValueType ; if ( param . defaultValue ) { defaultValueType = getTypeOfExpression ( param . defaultValue , annotatedType , EvaluatorFlags . ConvertEllipsisToAny ) . type ; } if ( annotatedType ) { if ( param . defaultValue && defaultValueType ) { const diagAddendum = new DiagnosticAddendum ( ) ; const typeVarMap = new TypeVarMap ( functionType . details . typeVarScopeId ) ; if ( containingClassType && containingClassType . details . typeVarScopeId !== undefined ) { if ( node . name . value === '__init__' || node . name . value === '__new__' ) { typeVarMap . addSolveForScope ( containingClassType . details . typeVarScopeId ) ; } } if ( ! canAssignType ( annotatedType , defaultValueType , diagAddendum , typeVarMap ) ) { const diag = addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . paramAssignmentMismatch ( ) . format ( { sourceType : printType ( defaultValueType ) , paramType : printType ( annotatedType ) , } ) + diagAddendum . getString ( ) , param . defaultValue ) ; if ( isNoneWithoutOptional && paramTypeNode ) { const addOptionalAction = { action : Commands . addMissingOptionalToParam , offsetOfTypeNode : paramTypeNode . start + 1 , } ; if ( diag ) { diag . addAction ( addOptionalAction ) ; } } } } paramType = annotatedType ; } const functionParam = { category : param . category , name : param . name ? param . name . value : undefined , hasDefault : ! ! param . defaultValue , defaultValueExpression : param . defaultValue , defaultType : defaultValueType , type : paramType || UnknownType . create ( ) , typeAnnotation : paramTypeNode , hasDeclaredType : ! ! paramTypeNode , } ; FunctionType . addParameter ( functionType , functionParam ) ; if ( param . name ) { const variadicParamType = transformVariadicParamType ( node , param . category , functionParam . type ) ; paramTypes . push ( variadicParamType ) ; } else { paramTypes . push ( functionParam . type ) ; } } ) ; if ( containingClassType ) { if ( functionType . details . parameters . length > 0 ) { const typeAnnotation = getTypeAnnotationForParameter ( node , 0 ) ; if ( ! typeAnnotation ) { const inferredParamType = inferFirstParamType ( functionType . details . flags , containingClassType ) ; if ( inferredParamType ) { functionType . details . parameters [ 0 ] . type = inferredParamType ; if ( ! isAnyOrUnknown ( inferredParamType ) ) { functionType . details . parameters [ 0 ] . isTypeInferred = true ; } paramTypes [ 0 ] = inferredParamType ; } } } } paramTypes . forEach ( ( paramType , index ) => { const paramNameNode = node . parameters [ index ] . name ; if ( paramNameNode ) { if ( isUnknown ( paramType ) ) { functionType . details . flags |= FunctionTypeFlags . UnannotatedParams ; } writeTypeCache ( paramNameNode , paramType , EvaluatorFlags . None , false ) ; } } ) ; if ( paramTypes . length >= 2 ) { const paramType1 = paramTypes [ paramTypes . length - 2 ] ; const paramType2 = paramTypes [ paramTypes . length - 1 ] ; if ( isParamSpec ( paramType1 ) && paramType1 . paramSpecAccess === 'args' && isParamSpec ( paramType2 ) && paramType2 . paramSpecAccess === 'kwargs' ) { functionType . details . flags |= FunctionTypeFlags . SkipArgsKwargsCompatibilityCheck ; } } if ( node . returnTypeAnnotation ) { functionType . details . declaredReturnType = UnknownType . create ( ) ; const returnType = getTypeOfAnnotation ( node . returnTypeAnnotation , { associateTypeVarsWithScope : true , disallowRecursiveTypeAlias : true , } ) ; functionType . details . declaredReturnType = returnType ; } else if ( node . functionAnnotationComment ) { functionType . details . declaredReturnType = UnknownType . create ( ) ; const returnType = getTypeOfAnnotation ( node . functionAnnotationComment . returnTypeAnnotation , { associateTypeVarsWithScope : true , disallowRecursiveTypeAlias : true , } ) ; functionType . details . declaredReturnType = returnType ; } else { if ( fileInfo . isStubFile ) { if ( node . name . value === '__init__' ) { functionType . details . declaredReturnType = NoneType . createInstance ( ) ; } else { functionType . details . declaredReturnType = UnknownType . create ( ) ; } } } const preDecoratedType = node . isAsync ? createAsyncFunction ( node , functionType ) : functionType ; let decoratedType = preDecoratedType ; let foundUnknown = false ; for ( let i = node . decorators . length - 1 ; i >= 0 ; i -- ) { const decorator = node . decorators [ i ] ; const newDecoratedType = applyFunctionDecorator ( decoratedType , functionType , decorator , node ) ; if ( containsUnknown ( newDecoratedType ) ) { if ( ! foundUnknown ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportUntypedFunctionDecorator , DiagnosticRule . reportUntypedFunctionDecorator , Localizer . Diagnostic . functionDecoratorTypeUnknown ( ) , node . decorators [ i ] . expression ) ; foundUnknown = true ; } } else { decoratedType = newDecoratedType ; } } if ( isFunction ( decoratedType ) ) { if ( FunctionType . isOverloaded ( decoratedType ) ) { node . parameters . forEach ( ( param ) => { markParamAccessed ( param ) ; } ) ; } decoratedType = addOverloadsToFunctionType ( node , decoratedType ) ; } writeTypeCache ( node . name , functionType , EvaluatorFlags . None , false ) ; writeTypeCache ( node , decoratedType , EvaluatorFlags . None , false ) ; return { functionType , decoratedType } ; } function adjustParameterAnnotatedType ( param , type ) { if ( param . defaultValue ?. nodeType === ParseNodeType . Constant && param . defaultValue . constType === KeywordType . None && ! isOptionalType ( type ) && ! AnalyzerNodeInfo . getFileInfo ( param ) . diagnosticRuleSet . strictParameterNoneValue ) { type = combineTypes ( [ type , NoneType . createInstance ( ) ] ) ; } return type ; } function inferFirstParamType ( flags , containingClassType ) { if ( ( flags & FunctionTypeFlags . StaticMethod ) === 0 ) { if ( containingClassType ) { const hasClsParam = ( flags & ( FunctionTypeFlags . ClassMethod | FunctionTypeFlags . ConstructorMethod ) ) !== 0 ; return synthesizeTypeVarForSelfCls ( containingClassType , hasClsParam ) ; } } return undefined ; } function transformVariadicParamType ( node , paramCategory , type ) { switch ( paramCategory ) { case ParameterCategory . Simple : { return type ; } case ParameterCategory . VarArgList : { if ( isTypeVar ( type ) && type . paramSpecAccess ) { return type ; } if ( tupleClassType && isInstantiableClass ( tupleClassType ) ) { let tupleTypeArgs ; let isForVariadic = false ; if ( isVariadicTypeVar ( type ) && type . isVariadicUnpacked ) { tupleTypeArgs = [ type ] ; isForVariadic = true ; } else { tupleTypeArgs = [ type , AnyType . create ( true ) ] ; } return ClassType . cloneAsInstance ( specializeTupleClass ( tupleClassType , tupleTypeArgs , true , true , isForVariadic ) ) ; } return UnknownType . create ( ) ; } case ParameterCategory . VarArgDictionary : { if ( isTypeVar ( type ) && type . paramSpecAccess ) { return type ; } const dictType = getBuiltInType ( node , 'dict' ) ; const strType = getBuiltInObject ( node , 'str' ) ; if ( isInstantiableClass ( dictType ) && isClassInstance ( strType ) ) { return ClassType . cloneAsInstance ( ClassType . cloneForSpecialization ( dictType , [ strType , type ] , true ) ) ; } return UnknownType . create ( ) ; } } } function getFunctionFlagsFromDecorators ( node , isInClass ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; let flags = FunctionTypeFlags . None ; if ( node . name . value === '__new__' && isInClass ) { flags |= FunctionTypeFlags . ConstructorMethod ; } if ( node . name . value === '__init_subclass__' && isInClass ) { flags |= FunctionTypeFlags . ClassMethod ; } for ( const decoratorNode of node . decorators ) { let evaluatorFlags = fileInfo . isStubFile ? EvaluatorFlags . AllowForwardReferences : EvaluatorFlags . None ; if ( decoratorNode . expression . nodeType !== ParseNodeType . Call ) { evaluatorFlags |= EvaluatorFlags . DoNotSpecialize ; } const decoratorType = getTypeOfExpression ( decoratorNode . expression , undefined , evaluatorFlags ) . type ; if ( isFunction ( decoratorType ) ) { if ( decoratorType . details . builtInName === 'abstractmethod' ) { if ( isInClass ) { flags |= FunctionTypeFlags . AbstractMethod ; } } else if ( decoratorType . details . builtInName === 'final' ) { flags |= FunctionTypeFlags . Final ; } } else if ( isInstantiableClass ( decoratorType ) ) { if ( ClassType . isBuiltIn ( decoratorType , 'staticmethod' ) ) { if ( isInClass ) { flags |= FunctionTypeFlags . StaticMethod ; } } else if ( ClassType . isBuiltIn ( decoratorType , 'classmethod' ) ) { if ( isInClass ) { flags |= FunctionTypeFlags . ClassMethod ; } } } } return flags ; } function applyFunctionDecorator ( inputFunctionType , undecoratedType , decoratorNode , functionNode ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( decoratorNode ) ; let evaluatorFlags = fileInfo . isStubFile ? EvaluatorFlags . AllowForwardReferences : EvaluatorFlags . None ; if ( decoratorNode . expression . nodeType !== ParseNodeType . Call ) { evaluatorFlags |= EvaluatorFlags . DoNotSpecialize ; } const decoratorType = getTypeOfExpression ( decoratorNode . expression , undefined , evaluatorFlags ) . type ; if ( ( isInstantiableClass ( decoratorType ) && ClassType . isSpecialBuiltIn ( decoratorType , 'overload' ) ) || ( isFunction ( decoratorType ) && decoratorType . details . builtInName === 'overload' ) ) { if ( isFunction ( inputFunctionType ) ) { inputFunctionType . details . flags |= FunctionTypeFlags . Overloaded ; undecoratedType . details . flags |= FunctionTypeFlags . Overloaded ; return inputFunctionType ; } } if ( decoratorNode . expression . nodeType === ParseNodeType . Call ) { const decoratorCallType = getTypeOfExpression ( decoratorNode . expression . leftExpression , undefined , evaluatorFlags | EvaluatorFlags . DoNotSpecialize ) . type ; if ( isFunction ( decoratorCallType ) ) { if ( decoratorCallType . details . name === '__dataclass_transform__' ) { undecoratedType . details . decoratorDataClassBehaviors = validateDataClassTransformDecorator ( evaluatorInterface , decoratorNode . expression ) ; return inputFunctionType ; } } } if ( isInstantiableClass ( decoratorType ) && ClassType . isSpecialBuiltIn ( decoratorType , 'no_type_check' ) ) { return inputFunctionType ; } let returnType = getTypeFromDecorator ( decoratorNode , inputFunctionType ) ; if ( isFunction ( decoratorType ) ) { if ( decoratorType . details . builtInName === 'abstractmethod' ) { return inputFunctionType ; } if ( decoratorNode . expression . nodeType === ParseNodeType . MemberAccess ) { const baseType = getTypeOfExpression ( decoratorNode . expression . leftExpression , undefined , evaluatorFlags | EvaluatorFlags . DoNotSpecialize ) . type ; if ( isProperty ( baseType ) ) { const memberName = decoratorNode . expression . memberName . value ; if ( memberName === 'setter' ) { if ( isFunction ( inputFunctionType ) ) { validatePropertyMethod ( inputFunctionType , decoratorNode ) ; return clonePropertyWithSetter ( baseType , inputFunctionType , functionNode ) ; } else { return inputFunctionType ; } } else if ( memberName === 'deleter' ) { if ( isFunction ( inputFunctionType ) ) { validatePropertyMethod ( inputFunctionType , decoratorNode ) ; return clonePropertyWithDeleter ( baseType , inputFunctionType , functionNode ) ; } else { return inputFunctionType ; } } } } } else if ( isInstantiableClass ( decoratorType ) ) { if ( ClassType . isBuiltIn ( decoratorType ) ) { switch ( decoratorType . details . name ) { case 'classmethod' : case 'staticmethod' : { return inputFunctionType ; } } } if ( ClassType . isPropertyClass ( decoratorType ) ) { if ( isFunction ( inputFunctionType ) ) { validatePropertyMethod ( inputFunctionType , decoratorNode ) ; return createProperty ( decoratorNode , decoratorType . details . name , inputFunctionType , ParseTreeUtils . getTypeSourceId ( decoratorNode ) ) ; } else if ( isClassInstance ( inputFunctionType ) ) { const callMember = lookUpObjectMember ( inputFunctionType , '__call__' ) ; if ( callMember ) { const memberType = getTypeOfMember ( callMember ) ; if ( isFunction ( memberType ) || isOverloadedFunction ( memberType ) ) { const boundMethod = bindFunctionToClassOrObject ( inputFunctionType , memberType ) ; if ( boundMethod && isFunction ( boundMethod ) ) { return createProperty ( decoratorNode , decoratorType . details . name , boundMethod , ParseTreeUtils . getTypeSourceId ( decoratorNode ) ) ; } } } return UnknownType . create ( ) ; } } } if ( isFunction ( inputFunctionType ) && isFunction ( returnType ) ) { returnType = FunctionType . clone ( returnType ) ; if ( FunctionType . isOverloaded ( inputFunctionType ) ) { returnType . details . flags |= FunctionTypeFlags . Overloaded ; } if ( ! returnType . details . docString ) { returnType . details . docString = inputFunctionType . details . docString ; } } return returnType ; } function validatePropertyMethod ( method , errorNode ) { if ( FunctionType . isStaticMethod ( method ) ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . propertyStaticMethod ( ) , errorNode ) ; } } function createProperty ( decoratorNode , className , fget , typeSourceId ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( decoratorNode ) ; const typeMetaclass = getBuiltInType ( decoratorNode , 'type' ) ; const propertyClass = ClassType . createInstantiable ( className , ParseTreeUtils . getClassFullName ( decoratorNode , fileInfo . moduleName , `__property_${ fget . details . name }` ) , fileInfo . moduleName , fileInfo . filePath , ClassTypeFlags . PropertyClass , typeSourceId , undefined , isInstantiableClass ( typeMetaclass ) ? typeMetaclass : UnknownType . create ( ) ) ; computeMroLinearization ( propertyClass ) ; const propertyObject = ClassType . cloneAsInstance ( propertyClass ) ; propertyClass . isAsymmetricDescriptor = false ; const fields = propertyClass . details . fields ; const fgetSymbol = Symbol . createWithType ( SymbolFlags . ClassMember , fget ) ; fields . set ( 'fget' , fgetSymbol ) ; if ( FunctionType . isClassMethod ( fget ) ) { propertyClass . details . flags |= ClassTypeFlags . ClassProperty ; } const getFunction1 = FunctionType . createInstance ( '__get__' , '' , '' , FunctionTypeFlags . SynthesizedMethod | FunctionTypeFlags . Overloaded ) ; getFunction1 . details . parameters . push ( { category : ParameterCategory . Simple , name : 'self' , type : propertyObject , hasDeclaredType : true , } ) ; getFunction1 . details . parameters . push ( { category : ParameterCategory . Simple , name : 'obj' , type : NoneType . createInstance ( ) , hasDeclaredType : true , } ) ; getFunction1 . details . parameters . push ( { category : ParameterCategory . Simple , name : 'objtype' , type : AnyType . create ( ) , hasDeclaredType : true , hasDefault : true , defaultType : AnyType . create ( ) , } ) ; getFunction1 . details . declaredReturnType = FunctionType . isClassMethod ( fget ) ? FunctionType . getSpecializedReturnType ( fget ) : propertyObject ; getFunction1 . details . declaration = fget . details . declaration ; const getFunction2 = FunctionType . createInstance ( '__get__' , '' , '' , FunctionTypeFlags . SynthesizedMethod | FunctionTypeFlags . Overloaded ) ; getFunction2 . details . parameters . push ( { category : ParameterCategory . Simple , name : 'self' , type : propertyObject , hasDeclaredType : true , } ) ; let objType = fget . details . parameters . length > 0 ? fget . details . parameters [ 0 ] . type : AnyType . create ( ) ; if ( isTypeVar ( objType ) && objType . details . isSynthesizedSelf ) { objType = makeTopLevelTypeVarsConcrete ( objType ) ; } getFunction2 . details . parameters . push ( { category : ParameterCategory . Simple , name : 'obj' , type : objType , hasDeclaredType : true , } ) ; getFunction2 . details . parameters . push ( { category : ParameterCategory . Simple , name : 'objtype' , type : AnyType . create ( ) , hasDeclaredType : true , hasDefault : true , defaultType : AnyType . create ( ) , } ) ; getFunction2 . details . declaredReturnType = FunctionType . getSpecializedReturnType ( fget ) ; getFunction2 . details . declaration = fget . details . declaration ; getFunction2 . details . typeVarScopeId = getTypeVarScopeId ( fget ) ; const getFunctionOverload = OverloadedFunctionType . create ( [ getFunction1 , getFunction2 ] ) ; const getSymbol = Symbol . createWithType ( SymbolFlags . ClassMember , getFunctionOverload ) ; fields . set ( '__get__' , getSymbol ) ; [ 'getter' , 'setter' , 'deleter' ] . forEach ( ( accessorName ) => { const accessorFunction = FunctionType . createInstance ( accessorName , '' , '' , FunctionTypeFlags . SynthesizedMethod ) ; accessorFunction . details . parameters . push ( { category : ParameterCategory . Simple , name : 'self' , type : AnyType . create ( ) , hasDeclaredType : true , } ) ; accessorFunction . details . parameters . push ( { category : ParameterCategory . Simple , name : 'accessor' , type : AnyType . create ( ) , hasDeclaredType : true , } ) ; accessorFunction . details . declaredReturnType = propertyObject ; const accessorSymbol = Symbol . createWithType ( SymbolFlags . ClassMember , accessorFunction ) ; fields . set ( accessorName , accessorSymbol ) ; } ) ; return propertyObject ; } function clonePropertyWithSetter ( prop , fset , errorNode ) { if ( ! isProperty ( prop ) ) { return prop ; } const classType = prop as ClassType ; const flagsToClone = classType . details . flags ; let isAsymmetricDescriptor = ! ! classType . isAsymmetricDescriptor ; const fileInfo = AnalyzerNodeInfo . getFileInfo ( errorNode ) ; if ( errorNode . parameters . length >= 2 ) { const typeAnnotation = getTypeAnnotationForParameter ( errorNode , 1 ) ; if ( typeAnnotation ) { const fgetType = getGetterTypeFromProperty ( classType , false ) ; if ( fgetType && ! isAnyOrUnknown ( fgetType ) ) { const fsetType = getTypeOfAnnotation ( typeAnnotation , { associateTypeVarsWithScope : true , disallowRecursiveTypeAlias : true , } ) ; if ( fileInfo . diagnosticRuleSet . reportPropertyTypeMismatch !== 'none' ) { const diag = new DiagnosticAddendum ( ) ; if ( ! canAssignType ( fgetType , fsetType , diag ) ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportPropertyTypeMismatch , DiagnosticRule . reportPropertyTypeMismatch , Localizer . Diagnostic . setterGetterTypeMismatch ( ) + diag . getString ( ) , typeAnnotation ) ; } } if ( ! isTypeSame ( fgetType , fsetType ) ) { isAsymmetricDescriptor = true ; } } } } const propertyClass = ClassType . createInstantiable ( classType . details . name , classType . details . fullName , classType . details . moduleName , AnalyzerNodeInfo . getFileInfo ( errorNode ) . filePath , flagsToClone , classType . details . typeSourceId , classType . details . declaredMetaclass , classType . details . effectiveMetaclass ) ; computeMroLinearization ( propertyClass ) ; const propertyObject = ClassType . cloneAsInstance ( propertyClass ) ; propertyClass . isAsymmetricDescriptor = isAsymmetricDescriptor ; const fields = propertyClass . details . fields ; classType . details . fields . forEach ( ( symbol , name ) => { if ( ! symbol . isIgnoredForProtocolMatch ( ) ) { fields . set ( name , symbol ) ; } } ) ; const fsetSymbol = Symbol . createWithType ( SymbolFlags . ClassMember , fset ) ; fields . set ( 'fset' , fsetSymbol ) ; const setFunction = FunctionType . createInstance ( '__set__' , '' , '' , FunctionTypeFlags . SynthesizedMethod ) ; setFunction . details . parameters . push ( { category : ParameterCategory . Simple , name : 'self' , type : prop , hasDeclaredType : true , } ) ; let objType = fset . details . parameters . length > 0 ? fset . details . parameters [ 0 ] . type : AnyType . create ( ) ; if ( isTypeVar ( objType ) && objType . details . isSynthesizedSelf ) { objType = makeTopLevelTypeVarsConcrete ( objType ) ; } setFunction . details . parameters . push ( { category : ParameterCategory . Simple , name : 'obj' , type : combineTypes ( [ objType , NoneType . createInstance ( ) ] ) , hasDeclaredType : true , } ) ; setFunction . details . declaredReturnType = NoneType . createInstance ( ) ; let setParamType = UnknownType . create ( ) ; if ( fset . details . parameters . length >= 2 && fset . details . parameters [ 1 ] . category === ParameterCategory . Simple && fset . details . parameters [ 1 ] . name ) { setParamType = fset . details . parameters [ 1 ] . type ; } setFunction . details . parameters . push ( { category : ParameterCategory . Simple , name : 'value' , type : setParamType , hasDeclaredType : true , } ) ; const setSymbol = Symbol . createWithType ( SymbolFlags . ClassMember , setFunction ) ; fields . set ( '__set__' , setSymbol ) ; return propertyObject ; } function clonePropertyWithDeleter ( prop , fdel , errorNode ) { if ( ! isProperty ( prop ) ) { return prop ; } const classType = prop as ClassType ; const propertyClass = ClassType . createInstantiable ( classType . details . name , classType . details . fullName , classType . details . moduleName , AnalyzerNodeInfo . getFileInfo ( errorNode ) . filePath , classType . details . flags , classType . details . typeSourceId , classType . details . declaredMetaclass , classType . details . effectiveMetaclass ) ; computeMroLinearization ( propertyClass ) ; const propertyObject = ClassType . cloneAsInstance ( propertyClass ) ; propertyClass . isAsymmetricDescriptor = classType . isAsymmetricDescriptor ?? false ; const fields = propertyClass . details . fields ; classType . details . fields . forEach ( ( symbol , name ) => { if ( ! symbol . isIgnoredForProtocolMatch ( ) ) { fields . set ( name , symbol ) ; } } ) ; const fdelSymbol = Symbol . createWithType ( SymbolFlags . ClassMember , fdel ) ; fields . set ( 'fdel' , fdelSymbol ) ; const delFunction = FunctionType . createInstance ( '__delete__' , '' , '' , FunctionTypeFlags . SynthesizedMethod ) ; delFunction . details . parameters . push ( { category : ParameterCategory . Simple , name : 'self' , type : prop , hasDeclaredType : true , } ) ; let objType = fdel . details . parameters . length > 0 ? fdel . details . parameters [ 0 ] . type : AnyType . create ( ) ; if ( isTypeVar ( objType ) && objType . details . isSynthesizedSelf ) { objType = makeTopLevelTypeVarsConcrete ( objType ) ; } delFunction . details . parameters . push ( { category : ParameterCategory . Simple , name : 'obj' , type : combineTypes ( [ objType , NoneType . createInstance ( ) ] ) , hasDeclaredType : true , } ) ; delFunction . details . declaredReturnType = NoneType . createInstance ( ) ; const delSymbol = Symbol . createWithType ( SymbolFlags . ClassMember , delFunction ) ; fields . set ( '__delete__' , delSymbol ) ; return propertyObject ; } function addOverloadsToFunctionType ( node , type ) { let functionDecl ; const decl = AnalyzerNodeInfo . getDeclaration ( node ) ; if ( decl ) { functionDecl = decl as FunctionDeclaration ; } const symbolWithScope = lookUpSymbolRecursive ( node , node . name . value , false ) ; if ( symbolWithScope ) { const decls = symbolWithScope . symbol . getDeclarations ( ) ; const declIndex = decls . findIndex ( ( decl ) => decl === functionDecl ) ; if ( declIndex > 0 ) { for ( let i = 0 ; i < declIndex ; i ++ ) { const decl = decls [ i ] ; if ( decl . type === DeclarationType . Function ) { getTypeOfFunction ( decl . node ) ; } } const overloadedTypes = [ ] ; const prevDecl = decls [ declIndex - 1 ] ; if ( prevDecl . type === DeclarationType . Function ) { const prevDeclDeclTypeInfo = getTypeOfFunction ( prevDecl . node ) ; if ( prevDeclDeclTypeInfo ) { if ( isFunction ( prevDeclDeclTypeInfo . decoratedType ) ) { if ( FunctionType . isOverloaded ( prevDeclDeclTypeInfo . decoratedType ) ) { overloadedTypes . push ( prevDeclDeclTypeInfo . decoratedType ) ; } } else if ( isOverloadedFunction ( prevDeclDeclTypeInfo . decoratedType ) ) { overloadedTypes . push ( ... prevDeclDeclTypeInfo . decoratedType . overloads ) ; } } } overloadedTypes . push ( type ) ; if ( overloadedTypes . length === 1 ) { return overloadedTypes [ 0 ] ; } const newOverload = OverloadedFunctionType . create ( overloadedTypes ) ; const prevOverload = overloadedTypes [ overloadedTypes . length - 2 ] ; const isPrevOverloadAbstract = FunctionType . isAbstractMethod ( prevOverload ) ; const isCurrentOverloadAbstract = FunctionType . isAbstractMethod ( type ) ; if ( isPrevOverloadAbstract !== isCurrentOverloadAbstract ) { addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( node ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . overloadAbstractMismatch ( ) . format ( { name : node . name . value } ) , node . name ) ; } return newOverload ; } } return type ; } function createAsyncFunction ( node , functionType ) { const awaitableFunctionType = FunctionType . clone ( functionType ) ; if ( functionType . details . declaredReturnType ) { awaitableFunctionType . details . declaredReturnType = createAwaitableReturnType ( node , functionType . details . declaredReturnType , ! ! functionType . details . declaration ?. isGenerator ) ; } awaitableFunctionType . details . flags |= FunctionTypeFlags . WrapReturnTypeInAwait ; return awaitableFunctionType ; } function createAwaitableReturnType ( node , returnType , isGenerator ) { let awaitableReturnType ; if ( isClassInstance ( returnType ) ) { if ( ClassType . isBuiltIn ( returnType ) ) { if ( returnType . details . name === 'Generator' ) { const asyncGeneratorType = getTypingType ( node , 'AsyncGenerator' ) ; if ( asyncGeneratorType && isInstantiableClass ( asyncGeneratorType ) ) { const typeArgs = [ ] ; const generatorTypeArgs = returnType . typeArguments ; if ( generatorTypeArgs && generatorTypeArgs . length > 0 ) { typeArgs . push ( generatorTypeArgs [ 0 ] ) ; } if ( generatorTypeArgs && generatorTypeArgs . length > 1 ) { typeArgs . push ( generatorTypeArgs [ 1 ] ) ; } awaitableReturnType = ClassType . cloneAsInstance ( ClassType . cloneForSpecialization ( asyncGeneratorType , typeArgs , true ) ) ; } } else if ( [ 'AsyncGenerator' , 'AsyncIterator' , 'AsyncIterable' ] . some ( ( name ) => name === returnType . details . name ) ) { awaitableReturnType = returnType ; } } } if ( ! awaitableReturnType || ! isGenerator ) { const coroutineType = getTypingType ( node , 'Coroutine' ) ; if ( coroutineType && isInstantiableClass ( coroutineType ) ) { awaitableReturnType = ClassType . cloneAsInstance ( ClassType . cloneForSpecialization ( coroutineType , [ AnyType . create ( ) , AnyType . create ( ) , returnType ] , true ) ) ; } else { awaitableReturnType = UnknownType . create ( ) ; } } return awaitableReturnType ; } function inferFunctionReturnType ( node , isAbstract ) { const returnAnnotation = node . returnTypeAnnotation || node . functionAnnotationComment ?. returnTypeAnnotation ; if ( returnAnnotation ) { return undefined ; } let inferredReturnType = readTypeCache ( node . suite , EvaluatorFlags . None ) ; if ( inferredReturnType ) { return inferredReturnType ; } if ( ! functionRecursionMap . has ( node . id ) ) { functionRecursionMap . set ( node . id , true ) ; try { let functionDecl ; const decl = AnalyzerNodeInfo . getDeclaration ( node ) ; if ( decl ) { functionDecl = decl as FunctionDeclaration ; } const functionNeverReturns = ! isAfterNodeReachable ( node ) ; const implicitlyReturnsNone = isAfterNodeReachable ( node . suite ) ; if ( AnalyzerNodeInfo . getFileInfo ( node ) . isStubFile ) { inferredReturnType = UnknownType . create ( ) ; } else { if ( functionNeverReturns ) { if ( isAbstract || methodAlwaysRaisesNotImplemented ( functionDecl ) ) { inferredReturnType = UnknownType . create ( ) ; } else { const noReturnClass = getTypingType ( node , 'NoReturn' ) ; if ( noReturnClass && isInstantiableClass ( noReturnClass ) ) { inferredReturnType = ClassType . cloneAsInstance ( noReturnClass ) ; } else { inferredReturnType = UnknownType . create ( ) ; } } } else { const inferredReturnTypes = [ ] ; if ( functionDecl ?. returnStatements ) { functionDecl . returnStatements . forEach ( ( returnNode ) => { if ( isNodeReachable ( returnNode ) ) { if ( returnNode . returnExpression ) { const returnType = getTypeOfExpression ( returnNode . returnExpression ) . type ; inferredReturnTypes . push ( returnType || UnknownType . create ( ) ) ; } else { inferredReturnTypes . push ( NoneType . createInstance ( ) ) ; } } } ) ; } if ( ! functionNeverReturns && implicitlyReturnsNone ) { inferredReturnTypes . push ( NoneType . createInstance ( ) ) ; } inferredReturnType = combineTypes ( inferredReturnTypes ) ; inferredReturnType = removeUnbound ( inferredReturnType ) ; inferredReturnType = removeNoReturnFromUnion ( inferredReturnType ) ; } if ( functionDecl ?. isGenerator ) { const inferredYieldTypes = [ ] ; if ( functionDecl . yieldStatements ) { functionDecl . yieldStatements . forEach ( ( yieldNode ) => { if ( isNodeReachable ( yieldNode ) ) { if ( yieldNode . nodeType === ParseNodeType . YieldFrom ) { const iteratorType = getTypeOfExpression ( yieldNode . expression ) . type ; const yieldType = getTypeFromIterator ( iteratorType , false , yieldNode ) ; inferredYieldTypes . push ( yieldType || UnknownType . create ( ) ) ; } else { if ( yieldNode . expression ) { const yieldType = getTypeOfExpression ( yieldNode . expression ) . type ; inferredYieldTypes . push ( yieldType || UnknownType . create ( ) ) ; } else { inferredYieldTypes . push ( NoneType . createInstance ( ) ) ; } } } } ) ; } if ( inferredYieldTypes . length === 0 ) { inferredYieldTypes . push ( NoneType . createInstance ( ) ) ; } const inferredYieldType = combineTypes ( inferredYieldTypes ) ; const generatorType = getTypingType ( node , 'Generator' ) ; if ( generatorType && isInstantiableClass ( generatorType ) ) { inferredReturnType = ClassType . cloneAsInstance ( ClassType . cloneForSpecialization ( generatorType , [ inferredYieldType , NoneType . createInstance ( ) , isNoReturnType ( inferredReturnType ) ? NoneType . createInstance ( ) : inferredReturnType , ] , true ) ) ; } else { inferredReturnType = UnknownType . create ( ) ; } } } writeTypeCache ( node . suite , inferredReturnType , EvaluatorFlags . None , false ) ; } finally { functionRecursionMap . delete ( node . id ) ; } } return inferredReturnType ; } function methodAlwaysRaisesNotImplemented ( functionDecl ? ) { if ( ! functionDecl || ! functionDecl . isMethod || functionDecl . returnStatements || functionDecl . yieldStatements || ! functionDecl . raiseStatements ) { return false ; } for ( const raiseStatement of functionDecl . raiseStatements ) { if ( ! raiseStatement . typeExpression || raiseStatement . valueExpression ) { return false ; } const raiseType = getTypeOfExpression ( raiseStatement . typeExpression ) . type ; const classType = isInstantiableClass ( raiseType ) ? raiseType : isClassInstance ( raiseType ) ? raiseType : undefined ; if ( ! classType || ! ClassType . isBuiltIn ( classType , 'NotImplementedError' ) ) { return false ; } } return true ; } function evaluateTypesForForStatement ( node ) { if ( readTypeCache ( node , EvaluatorFlags . None ) ) { return ; } const iteratorTypeResult = getTypeOfExpression ( node . iterableExpression ) ; const iteratedType = getTypeFromIterator ( iteratorTypeResult . type , ! ! node . isAsync , node . iterableExpression ) || UnknownType . create ( ) ; assignTypeToExpression ( node . targetExpression , iteratedType , ! ! iteratorTypeResult . isIncomplete , node . targetExpression ) ; writeTypeCache ( node , iteratedType , EvaluatorFlags . None , ! ! iteratorTypeResult . isIncomplete ) ; } function evaluateTypesForExceptStatement ( node ) { assert ( node . typeExpression !== undefined ) ; if ( readTypeCache ( node , EvaluatorFlags . None ) ) { return ; } const exceptionTypes = getTypeOfExpression ( node . typeExpression ! ) . type ; function getExceptionType ( exceptionType , errorNode ) { exceptionType = makeTopLevelTypeVarsConcrete ( exceptionType ) ; if ( isAnyOrUnknown ( exceptionType ) ) { return exceptionType ; } if ( isInstantiableClass ( exceptionType ) ) { return ClassType . cloneAsInstance ( exceptionType ) ; } if ( isClassInstance ( exceptionType ) ) { const iterableType = getTypeFromIterator ( exceptionType , false , errorNode ) || UnknownType . create ( ) ; return mapSubtypes ( iterableType , ( subtype ) => { if ( isAnyOrUnknown ( subtype ) ) { return subtype ; } return UnknownType . create ( ) ; } ) ; } return UnknownType . create ( ) ; } const targetType = mapSubtypes ( exceptionTypes , ( subType ) => { const tupleType = getSpecializedTupleType ( subType ) ; if ( tupleType && tupleType . tupleTypeArguments ) { const entryTypes = tupleType . tupleTypeArguments . map ( ( t ) => { return getExceptionType ( t , node . typeExpression ! ) ; } ) ; return combineTypes ( entryTypes ) ; } return getExceptionType ( subType , node . typeExpression ! ) ; } ) ; if ( node . name ) { assignTypeToExpression ( node . name , targetType , false , node . name ) ; } writeTypeCache ( node , targetType , EvaluatorFlags . None , false ) ; } function evaluateTypesForWithStatement ( node ) { if ( readTypeCache ( node , EvaluatorFlags . None ) ) { return ; } const exprTypeResult = getTypeOfExpression ( node . expression ) ; let exprType = exprTypeResult . type ; const isAsync = node . parent && node . parent . nodeType === ParseNodeType . With && ! ! node . parent . isAsync ; if ( isOptionalType ( exprType ) ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportOptionalContextManager , DiagnosticRule . reportOptionalContextManager , Localizer . Diagnostic . noneNotUsableWith ( ) , node . expression ) ; exprType = removeNoneFromUnion ( exprType ) ; } const enterMethodName = isAsync ? '__aenter__' : '__enter__' ; const scopedType = mapSubtypes ( exprType , ( subtype ) => { subtype = makeTopLevelTypeVarsConcrete ( subtype ) ; if ( isAnyOrUnknown ( subtype ) ) { return subtype ; } const diag = new DiagnosticAddendum ( ) ; const additionalHelp = new DiagnosticAddendum ( ) ; if ( isClassInstance ( subtype ) ) { const enterType = getTypeFromObjectMember ( node . expression , subtype , enterMethodName , { method : 'get' } , diag ) ?. type ; if ( enterType ) { let memberReturnType ; if ( isFunction ( enterType ) ) { memberReturnType = getFunctionEffectiveReturnType ( enterType ) ; } else { memberReturnType = UnknownType . create ( ) ; } if ( isAsync ) { memberReturnType = getTypeFromAwaitable ( memberReturnType , node ) ; } return memberReturnType ; } if ( ! isAsync ) { const memberType = getTypeFromObjectMember ( node . expression , subtype , '__aenter__' , { method : 'get' } , diag ) ; if ( memberType ) { additionalHelp . addMessage ( Localizer . DiagnosticAddendum . asyncHelp ( ) ) ; } } } const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeNotUsableWith ( ) . format ( { type : printType ( subtype ) , method : enterMethodName } ) + additionalHelp . getString ( ) , node . expression ) ; return UnknownType . create ( ) ; } ) ; const exitMethodName = isAsync ? '__aexit__' : '__exit__' ; doForEachSubtype ( exprType , ( subtype ) => { subtype = makeTopLevelTypeVarsConcrete ( subtype ) ; if ( isAnyOrUnknown ( subtype ) ) { return ; } const diag = new DiagnosticAddendum ( ) ; if ( isClassInstance ( subtype ) ) { const exitType = getTypeFromObjectMember ( node . expression , subtype , exitMethodName , { method : 'get' } , diag ) ; if ( exitType ) { return ; } } const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeNotUsableWith ( ) . format ( { type : printType ( subtype ) , method : exitMethodName } ) , node . expression ) ; } ) ; if ( node . target ) { assignTypeToExpression ( node . target , scopedType , ! ! exprTypeResult . isIncomplete , node . target ) ; } writeTypeCache ( node , scopedType , EvaluatorFlags . None , ! ! exprTypeResult . isIncomplete ) ; } function evaluateTypesForImportAs ( node ) { if ( readTypeCache ( node , EvaluatorFlags . None ) ) { return ; } let symbolNameNode ; if ( node . alias ) { symbolNameNode = node . alias ; } else { symbolNameNode = node . module . nameParts [ 0 ] ; } if ( ! symbolNameNode ) { return ; } let symbolType = getAliasedSymbolTypeForName ( node , symbolNameNode . value ) || UnknownType . create ( ) ; const cachedModuleType = readTypeCache ( node , EvaluatorFlags . None ) as ModuleType ; if ( cachedModuleType && isModule ( cachedModuleType ) && symbolType ) { if ( isTypeSame ( symbolType , cachedModuleType ) ) { symbolType = cachedModuleType ; } } assignTypeToNameNode ( symbolNameNode , symbolType , false ) ; writeTypeCache ( node , symbolType , EvaluatorFlags . None , false ) ; } function evaluateTypesForImportFromAs ( node ) { if ( readTypeCache ( node , EvaluatorFlags . None ) ) { return ; } const aliasNode = node . alias || node . name ; const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; if ( node . alias ?. value === node . name . value ) { const symbolInScope = lookUpSymbolRecursive ( node , node . name . value , true ) ; if ( symbolInScope ) { setSymbolAccessed ( fileInfo , symbolInScope . symbol , node ) ; } } let symbolType = getAliasedSymbolTypeForName ( node , aliasNode . value ) ; if ( ! symbolType ) { const parentNode = node . parent as ImportFromNode ; assert ( parentNode && parentNode . nodeType === ParseNodeType . ImportFrom ) ; assert ( ! parentNode . isWildcardImport ) ; const importInfo = AnalyzerNodeInfo . getImportInfo ( parentNode . module ) ; if ( importInfo && importInfo . isImportFound && ! importInfo . isNativeLib ) { const resolvedPath = importInfo . resolvedPaths [ importInfo . resolvedPaths . length - 1 ] ; const importLookupInfo = importLookup ( resolvedPath ) ; let reportError = false ; if ( importLookupInfo ) { reportError = true ; if ( fileInfo . executionEnvironment . pythonVersion >= PythonVersion . V3_7 || fileInfo . isStubFile ) { const getAttrSymbol = importLookupInfo . symbolTable . get ( '__getattr__' ) ; if ( getAttrSymbol ) { const getAttrType = getEffectiveTypeOfSymbol ( getAttrSymbol ) ; if ( isFunction ( getAttrType ) ) { symbolType = getFunctionEffectiveReturnType ( getAttrType ) ; reportError = false ; } } } } else if ( ! resolvedPath ) { reportError = true ; } if ( reportError ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . importSymbolUnknown ( ) . format ( { name : node . name . value } ) , node . name ) ; } } if ( ! symbolType ) { symbolType = UnknownType . create ( ) ; } } assignTypeToNameNode ( aliasNode , symbolType , false ) ; writeTypeCache ( node , symbolType , EvaluatorFlags . None , false ) ; } function evaluateTypesForMatchNode ( node ) { if ( readTypeCache ( node , EvaluatorFlags . None ) ) { return ; } const subjectTypeResult = getTypeOfExpression ( node . subjectExpression ) ; let subjectType = subjectTypeResult . type ; for ( const caseStatement of node . cases ) { if ( ! caseStatement . guardExpression ) { subjectType = narrowTypeBasedOnPattern ( evaluatorInterface , subjectType , caseStatement . pattern , false ) ; } } writeTypeCache ( node , subjectType , EvaluatorFlags . None , ! ! subjectTypeResult . isIncomplete ) ; } function evaluateTypesForCaseNode ( node ) { if ( readTypeCache ( node , EvaluatorFlags . None ) ) { return ; } if ( ! node . parent || node . parent . nodeType !== ParseNodeType . Match ) { fail ( 'Expected parent of case statement to be match statement' ) ; return ; } const subjectTypeResult = getTypeOfExpression ( node . parent . subjectExpression ) ; let subjectType = subjectTypeResult . type ; for ( const caseStatement of node . parent . cases ) { if ( caseStatement === node ) { break ; } if ( ! caseStatement . guardExpression ) { subjectType = narrowTypeBasedOnPattern ( evaluatorInterface , subjectType , caseStatement . pattern , false ) ; } } let subjectIsObject = false ; doForEachSubtype ( makeTopLevelTypeVarsConcrete ( subjectType ) , ( subtype ) => { if ( isClassInstance ( subtype ) && ClassType . isBuiltIn ( subtype , 'object' ) ) { subjectIsObject = true ; } } ) ; subjectType = narrowTypeBasedOnPattern ( evaluatorInterface , subjectType , node . pattern , true ) ; assignTypeToPatternTargets ( evaluatorInterface , subjectType , ! ! subjectTypeResult . isIncomplete , subjectIsObject , node . pattern ) ; writeTypeCache ( node , subjectType , EvaluatorFlags . None , ! ! subjectTypeResult . isIncomplete ) ; } function evaluateTypesForImportFrom ( node ) { if ( readTypeCache ( node , EvaluatorFlags . None ) ) { return ; } const symbolNameNode = node . module . nameParts [ 0 ] ; let symbolType = getAliasedSymbolTypeForName ( node , symbolNameNode . value ) || UnknownType . create ( ) ; const cachedModuleType = readTypeCache ( node , EvaluatorFlags . None ) as ModuleType ; if ( cachedModuleType && isModule ( cachedModuleType ) && symbolType ) { if ( isTypeSame ( symbolType , cachedModuleType ) ) { symbolType = cachedModuleType ; } } assignTypeToNameNode ( symbolNameNode , symbolType , false ) ; writeTypeCache ( node , symbolType , EvaluatorFlags . None , false ) ; } function getAliasedSymbolTypeForName ( node , name ) { const symbolWithScope = lookUpSymbolRecursive ( node , name , true ) ; if ( ! symbolWithScope ) { return undefined ; } const filteredDecls = symbolWithScope . symbol . getDeclarations ( ) . filter ( ( decl ) => ParseTreeUtils . isNodeContainedWithin ( node , decl . node ) && decl . type === DeclarationType . Alias ) ; let aliasDecl = filteredDecls . length > 0 ? filteredDecls [ filteredDecls . length - 1 ] : undefined ; if ( ! aliasDecl ) { aliasDecl = symbolWithScope . symbol . getDeclarations ( ) . find ( ( decl ) => decl . type === DeclarationType . Alias ) ; } if ( ! aliasDecl ) { return undefined ; } assert ( aliasDecl . type === DeclarationType . Alias ) ; const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; const resolvedAliasInfo = resolveAliasDeclarationWithInfo ( aliasDecl , true , fileInfo . isStubFile ) ; if ( ! resolvedAliasInfo ) { return undefined ; } if ( ! resolvedAliasInfo . declaration ) { return evaluatorOptions . evaluateUnknownImportsAsAny ? AnyType . create ( ) : UnknownType . create ( ) ; } if ( node . nodeType === ParseNodeType . ImportFromAs ) { if ( resolvedAliasInfo . isPrivate ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportPrivateUsage , DiagnosticRule . reportPrivateUsage , Localizer . Diagnostic . privateUsedOutsideOfModule ( ) . format ( { name : node . name . value , } ) , node . name ) ; } if ( resolvedAliasInfo . privatePyTypedImporter ) { const diag = new DiagnosticAddendum ( ) ; if ( resolvedAliasInfo . privatePyTypedImported ) { diag . addMessage ( Localizer . DiagnosticAddendum . privateImportFromPyTypedSource ( ) . format ( { module : resolvedAliasInfo . privatePyTypedImported , } ) ) ; } addDiagnostic ( fileInfo . diagnosticRuleSet . reportPrivateImportUsage , DiagnosticRule . reportPrivateImportUsage , Localizer . Diagnostic . privateImportFromPyTypedModule ( ) . format ( { name : node . name . value , module : resolvedAliasInfo . privatePyTypedImporter , } ) + diag . getString ( ) , node . name ) ; } } return getInferredTypeOfDeclaration ( aliasDecl ) ; } function evaluateTypesForExpressionInContext ( node ) { let lastContextualExpression = node ; let curNode = node ; function isContextual ( node ) { if ( node . nodeType === ParseNodeType . Parameter && node . parent ?. nodeType === ParseNodeType . Lambda ) { return true ; } if ( node . nodeType === ParseNodeType . Argument && ( node . parent ?. nodeType === ParseNodeType . Call || node . parent ?. nodeType === ParseNodeType . Index ) ) { return true ; } if ( node . parent ?. nodeType === ParseNodeType . TypeAnnotation ) { return true ; } if ( node . parent ?. nodeType === ParseNodeType . Parameter && ( node === node . parent . typeAnnotation || node === node . parent . typeAnnotationComment ) ) { return true ; } return ( node . nodeType === ParseNodeType . Call || node . nodeType === ParseNodeType . Index || node . nodeType === ParseNodeType . Dictionary || node . nodeType === ParseNodeType . FormatString || node . nodeType === ParseNodeType . List || node . nodeType === ParseNodeType . Lambda || node . nodeType === ParseNodeType . MemberAccess || node . nodeType === ParseNodeType . Set || node . nodeType === ParseNodeType . String || node . nodeType === ParseNodeType . StringList || node . nodeType === ParseNodeType . Tuple || node . nodeType === ParseNodeType . Unpack || node . nodeType === ParseNodeType . DictionaryKeyEntry || node . nodeType === ParseNodeType . DictionaryExpandEntry || node . nodeType === ParseNodeType . ListComprehension || node . nodeType === ParseNodeType . ListComprehensionFor || node . nodeType === ParseNodeType . ListComprehensionIf || node . nodeType === ParseNodeType . PatternSequence || node . nodeType === ParseNodeType . PatternLiteral || node . nodeType === ParseNodeType . PatternClass || node . nodeType === ParseNodeType . PatternClassArgument || node . nodeType === ParseNodeType . PatternAs || node . nodeType === ParseNodeType . PatternCapture || node . nodeType === ParseNodeType . PatternMapping || node . nodeType === ParseNodeType . PatternValue || node . nodeType === ParseNodeType . PatternMappingKeyEntry || node . nodeType === ParseNodeType . PatternMappingExpandEntry || node . nodeType === ParseNodeType . ArrowCallable ) ; } if ( node . nodeType === ParseNodeType . Name && node . parent ) { if ( node . parent . nodeType === ParseNodeType . Function && node . parent . name === node ) { getTypeOfFunction ( node . parent ) ; return ; } else if ( node . parent . nodeType === ParseNodeType . Class && node . parent . name === node ) { getTypeOfClass ( node . parent ) ; return ; } else if ( node . parent . nodeType === ParseNodeType . Global || node . parent . nodeType === ParseNodeType . Nonlocal ) { getTypeOfExpression ( node , undefined , EvaluatorFlags . AllowForwardReferences ) ; return ; } } while ( curNode ) { const isNodeContextual = isContextual ( curNode ) ; if ( ! isNodeContextual && ! isExpressionNode ( curNode ) ) { break ; } if ( isNodeContextual ) { lastContextualExpression = curNode as ExpressionNode ; } curNode = curNode . parent ; } const parent = lastContextualExpression . parent ! ; if ( parent . nodeType === ParseNodeType . Assignment ) { if ( lastContextualExpression === parent . typeAnnotationComment ) { getTypeOfAnnotation ( lastContextualExpression , { isVariableAnnotation : true , allowFinal : ParseTreeUtils . isFinalAllowedForAssignmentTarget ( parent . leftExpression ) , allowClassVar : ParseTreeUtils . isClassVarAllowedForAssignmentTarget ( parent . leftExpression ) , } ) ; } else { evaluateTypesForAssignmentStatement ( parent ) ; } return ; } else if ( parent . nodeType === ParseNodeType . Del ) { verifyDeleteExpression ( lastContextualExpression ) ; return ; } if ( parent . nodeType === ParseNodeType . AugmentedAssignment ) { evaluateTypesForAugmentedAssignment ( parent ) ; return ; } if ( parent . nodeType === ParseNodeType . Decorator ) { if ( parent . parent ?. nodeType === ParseNodeType . Class ) { getTypeOfClass ( parent . parent ) ; } else if ( parent . parent ?. nodeType === ParseNodeType . Function ) { getTypeOfFunction ( parent . parent ) ; } return ; } const evaluateTypeAnnotationExpression = ( node ) => { const annotationParent = node . parent ; if ( annotationParent ?. nodeType === ParseNodeType . Assignment && annotationParent . leftExpression === parent ) { evaluateTypesForAssignmentStatement ( annotationParent ) ; } else { const annotationType = getTypeOfAnnotation ( node . typeAnnotation , { isVariableAnnotation : true , allowFinal : ParseTreeUtils . isFinalAllowedForAssignmentTarget ( node . valueExpression ) , allowClassVar : ParseTreeUtils . isClassVarAllowedForAssignmentTarget ( node . valueExpression ) , } ) ; writeTypeCache ( node . valueExpression , annotationType , EvaluatorFlags . None , false ) ; } } ; if ( parent . nodeType === ParseNodeType . Case && lastContextualExpression !== parent . guardExpression ) { evaluateTypesForCaseNode ( parent ) ; return ; } if ( parent . nodeType === ParseNodeType . TypeAnnotation ) { evaluateTypeAnnotationExpression ( parent ) ; return ; } if ( parent . nodeType === ParseNodeType . Parameter && lastContextualExpression !== parent . defaultValue ) { evaluateTypeOfParameter ( parent ) ; return ; } if ( parent . nodeType === ParseNodeType . Function ) { if ( lastContextualExpression === parent . returnTypeAnnotation || lastContextualExpression === parent . functionAnnotationComment ) { getTypeOfAnnotation ( lastContextualExpression , { associateTypeVarsWithScope : true , disallowRecursiveTypeAlias : true , } ) ; return ; } } if ( parent . nodeType === ParseNodeType . ModuleName ) { return ; } if ( parent . nodeType === ParseNodeType . Argument && lastContextualExpression === parent . name ) { return ; } if ( parent . nodeType === ParseNodeType . Argument && parent . parent ?. nodeType === ParseNodeType . Class ) { getTypeOfClass ( parent . parent ) ; return ; } if ( parent . nodeType === ParseNodeType . Return && parent . returnExpression ) { const enclosingFunctionNode = ParseTreeUtils . getEnclosingFunction ( node ) ; const declaredReturnType = enclosingFunctionNode ? getFunctionDeclaredReturnType ( enclosingFunctionNode ) : undefined ; getTypeOfExpression ( parent . returnExpression , declaredReturnType , EvaluatorFlags . None ) ; return ; } const nodeToEvaluate = isExpressionNode ( parent ) && parent . nodeType !== ParseNodeType . Error ? ( parent as ExpressionNode ) : lastContextualExpression ; if ( nodeToEvaluate . nodeType === ParseNodeType . TypeAnnotation ) { evaluateTypeAnnotationExpression ( nodeToEvaluate ) ; } else { const fileInfo = AnalyzerNodeInfo . getFileInfo ( nodeToEvaluate ) ; const flags = fileInfo . isStubFile ? EvaluatorFlags . AllowForwardReferences : EvaluatorFlags . None ; getTypeOfExpression ( nodeToEvaluate , undefined , flags ) ; } } function evaluateTypeOfParameter ( node ) { assert ( node . name !== undefined ) ; const parent = node . parent ! ; if ( parent . nodeType === ParseNodeType . Lambda ) { evaluateTypesForExpressionInContext ( parent ) ; return ; } assert ( parent . nodeType === ParseNodeType . Function ) ; const functionNode = parent as FunctionNode ; const paramIndex = functionNode . parameters . findIndex ( ( param ) => param === node ) ; const typeAnnotation = getTypeAnnotationForParameter ( functionNode , paramIndex ) ; if ( typeAnnotation ) { const param = functionNode . parameters [ paramIndex ] ; const annotatedType = getTypeOfAnnotation ( typeAnnotation , { associateTypeVarsWithScope : true , allowTypeVarTuple : functionNode . parameters [ paramIndex ] . category === ParameterCategory . VarArgList , disallowRecursiveTypeAlias : true , } ) ; writeTypeCache ( node . name ! , transformVariadicParamType ( node , node . category , adjustParameterAnnotatedType ( param , annotatedType ) ) , EvaluatorFlags . None , false ) ; return ; } if ( paramIndex === 0 ) { const containingClassNode = ParseTreeUtils . getEnclosingClass ( functionNode , true ) ; if ( containingClassNode ) { const classInfo = getTypeOfClass ( containingClassNode ) ; if ( classInfo ) { const functionFlags = getFunctionFlagsFromDecorators ( functionNode , true ) ; const inferredParamType = inferFirstParamType ( functionFlags , classInfo . classType ) ; writeTypeCache ( node . name ! , inferredParamType || UnknownType . create ( ) , EvaluatorFlags . None , false ) ; return ; } } } writeTypeCache ( node . name ! , transformVariadicParamType ( node , node . category , UnknownType . create ( ) ) , EvaluatorFlags . None , false ) ; } function evaluateTypesForStatement ( node ) { initializedBasicTypes ( node ) ; let curNode = node ; while ( curNode ) { switch ( curNode . nodeType ) { case ParseNodeType . Assignment : { const isInAssignmentChain = curNode . parent && ( curNode . parent . nodeType === ParseNodeType . Assignment || curNode . parent . nodeType === ParseNodeType . AssignmentExpression || curNode . parent . nodeType === ParseNodeType . AugmentedAssignment ) && curNode . parent . rightExpression === curNode ; if ( ! isInAssignmentChain ) { evaluateTypesForAssignmentStatement ( curNode ) ; return ; } break ; } case ParseNodeType . AssignmentExpression : { getTypeOfExpression ( curNode ) ; return ; } case ParseNodeType . AugmentedAssignment : { evaluateTypesForAugmentedAssignment ( curNode ) ; return ; } case ParseNodeType . Class : { getTypeOfClass ( curNode ) ; return ; } case ParseNodeType . Parameter : { evaluateTypeOfParameter ( curNode ) ; return ; } case ParseNodeType . Lambda : { evaluateTypesForExpressionInContext ( curNode ) ; return ; } case ParseNodeType . Function : { getTypeOfFunction ( curNode ) ; return ; } case ParseNodeType . For : { evaluateTypesForForStatement ( curNode ) ; return ; } case ParseNodeType . Except : { evaluateTypesForExceptStatement ( curNode ) ; return ; } case ParseNodeType . WithItem : { evaluateTypesForWithStatement ( curNode ) ; return ; } case ParseNodeType . ListComprehensionFor : { const listComprehension = curNode . parent as ListComprehensionNode ; assert ( listComprehension . nodeType === ParseNodeType . ListComprehension ) ; evaluateTypesForExpressionInContext ( listComprehension ) ; return ; } case ParseNodeType . ImportAs : { evaluateTypesForImportAs ( curNode ) ; return ; } case ParseNodeType . ImportFromAs : { evaluateTypesForImportFromAs ( curNode ) ; return ; } case ParseNodeType . ImportFrom : { evaluateTypesForImportFrom ( curNode ) ; return ; } case ParseNodeType . Case : { evaluateTypesForCaseNode ( curNode ) ; return ; } } curNode = curNode . parent ; } fail ( 'Unexpected statement' ) ; return undefined ; } function evaluateTypeForSubnode ( subnode , callback ) { let subnodeType = readTypeCache ( subnode , undefined ) ; if ( subnodeType ) { return { node : subnode , type : subnodeType } ; } const oldIncompleteCache = incompleteTypeCache ; try { incompleteTypeCache = new Map < number , CachedType > ( ) ; callback ( ) ; subnodeType = readTypeCache ( subnode , undefined ) ; if ( subnodeType ) { return { node : subnode , type : subnodeType } ; } subnodeType = incompleteTypeCache . get ( subnode . id ) as Type | undefined ; if ( subnodeType ) { return { node : subnode , type : subnodeType , isIncomplete : true } ; } } finally { incompleteTypeCache = oldIncompleteCache ; } return undefined ; } function getCodeFlowAnalyzerForNode ( nodeId ) { let analyzer = codeFlowAnalyzerCache . get ( nodeId ) ; if ( ! analyzer ) { analyzer = codeFlowEngine . createCodeFlowAnalyzer ( ) ; codeFlowAnalyzerCache . set ( nodeId , analyzer ) ; } return analyzer ; } function getFlowTypeOfReference ( reference , targetSymbolId , initialType , isInitialTypeIncomplete , startNode ? ) { const referenceKey = createKeyForReference ( reference ) ; const executionNode = ParseTreeUtils . getExecutionScopeNode ( startNode ?. parent ?? reference ) ; const codeFlowExpressions = AnalyzerNodeInfo . getCodeFlowExpressions ( executionNode ) ; if ( ! codeFlowExpressions || ! codeFlowExpressions . has ( referenceKey ) ) { return { type : undefined , usedOuterScopeAlias : false , isIncomplete : false } ; } let analyzer ; if ( isNodeInReturnTypeInferenceContext ( executionNode ) ) { analyzer = getCodeFlowAnalyzerForReturnTypeInferenceContext ( ) ; } else { analyzer = getCodeFlowAnalyzerForNode ( executionNode . id ) ; } const flowNode = AnalyzerNodeInfo . getFlowNode ( startNode ?? reference ) ; if ( flowNode === undefined ) { return { type : undefined , usedOuterScopeAlias : false , isIncomplete : false } ; } return getTypeFromCodeFlow ( analyzer , flowNode ! , reference , targetSymbolId , initialType , isInitialTypeIncomplete ) ; } function getTypeFromCodeFlow ( analyzer , flowNode , reference , targetSymbolId , initialType , isInitialTypeIncomplete ) { incompleteTypeTracker . enterTrackingScope ( ) ; let codeFlowResult ; try { codeFlowResult = analyzer . getTypeFromCodeFlow ( flowNode ! , reference , targetSymbolId , initialType , isInitialTypeIncomplete ) ; } finally { incompleteTypeTracker . exitTrackingScope ( ) ; } if ( codeFlowResult . isIncomplete ) { incompleteTypeTracker . enableUndoTracking ( ) ; } return codeFlowResult ; } function createSpecializedClassType ( classType , typeArgs , flags , errorNode ) { if ( ClassType . isSpecialBuiltIn ( classType ) ) { const aliasedName = classType . aliasName || classType . details . name ; switch ( aliasedName ) { case 'Callable' : { return createCallableType ( typeArgs , errorNode ) ; } case 'Optional' : { return createOptionalType ( classType , errorNode , typeArgs , flags ) ; } case 'Type' : { if ( typeArgs ?. length === 1 && isAnyOrUnknown ( typeArgs [ 0 ] . type ) && typeClassType && isInstantiableClass ( typeClassType ) ) { return typeClassType ; } let typeType = createSpecialType ( classType , typeArgs , 1 ) ; if ( isInstantiableClass ( typeType ) ) { typeType = explodeGenericClass ( typeType ) ; } return typeType ; } case 'ClassVar' : { return createClassVarType ( classType , errorNode , typeArgs , flags ) ; } case 'Protocol' : { return createSpecialType ( classType , typeArgs , undefined , true ) ; } case 'Tuple' : { return createSpecialType ( classType , typeArgs , undefined ) ; } case 'Union' : { return createUnionType ( classType , errorNode , typeArgs , flags ) ; } case 'Generic' : { return createGenericType ( classType , errorNode , typeArgs , flags ) ; } case 'Final' : { return createFinalType ( classType , errorNode , typeArgs , flags ) ; } case 'Annotated' : { return createAnnotatedType ( errorNode , typeArgs ) ; } case 'Concatenate' : { return createConcatenateType ( errorNode , classType , typeArgs ) ; } case 'TypeGuard' : { return createTypeGuardType ( errorNode , classType , typeArgs ) ; } case 'Unpack' : { return createUnpackType ( errorNode , typeArgs ) ; } case 'Required' : case 'NotRequired' : { return createRequiredType ( classType , errorNode , aliasedName === 'Required' , typeArgs , flags ) ; } case 'Self' : { return createSelfType ( classType , errorNode , typeArgs ) ; } } } const fileInfo = AnalyzerNodeInfo . getFileInfo ( errorNode ) ; if ( fileInfo . isStubFile || fileInfo . executionEnvironment . pythonVersion >= PythonVersion . V3_9 || isAnnotationEvaluationPostponed ( AnalyzerNodeInfo . getFileInfo ( errorNode ) ) || ( flags & EvaluatorFlags . AllowForwardReferences ) !== 0 ) { if ( ClassType . isBuiltIn ( classType , 'type' ) && typeArgs ) { if ( typeArgs . length === 1 && isAnyOrUnknown ( typeArgs [ 0 ] . type ) ) { return classType ; } const typeClass = getTypingType ( errorNode , 'Type' ) ; if ( typeClass && isInstantiableClass ( typeClass ) ) { let typeType = createSpecialType ( typeClass , typeArgs , 1 , undefined , true ) ; if ( isInstantiableClass ( typeType ) ) { typeType = explodeGenericClass ( typeType ) ; } return typeType ; } } if ( isTupleClass ( classType ) ) { return createSpecialType ( classType , typeArgs , undefined , undefined , true ) ; } } let typeArgCount = typeArgs ? typeArgs . length : 0 ; const typeParameters = ClassType . isPseudoGenericClass ( classType ) ? [ ] : ClassType . getTypeParameters ( classType ) ; if ( typeParameters . length === 0 && typeArgCount === 0 ) { return classType ; } const variadicTypeParamIndex = typeParameters . findIndex ( ( param ) => isVariadicTypeVar ( param ) ) ; if ( typeArgs ) { if ( typeArgCount > typeParameters . length ) { if ( ! ClassType . isPartiallyConstructed ( classType ) && ! ClassType . isTupleClass ( classType ) ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( errorNode ) ; if ( typeParameters . length === 0 ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeArgsExpectingNone ( ) . format ( { name : classType . aliasName || classType . details . name , } ) , typeArgs [ typeParameters . length ] . node ) ; } else if ( typeParameters . length !== 1 || ! isParamSpec ( typeParameters [ 0 ] ) ) { addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeArgsTooMany ( ) . format ( { name : classType . aliasName || classType . details . name , expected : typeParameters . length , received : typeArgCount , } ) , typeArgs [ typeParameters . length ] . node ) ; } } typeArgCount = typeParameters . length ; } else if ( typeArgCount < typeParameters . length ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( errorNode ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeArgsTooFew ( ) . format ( { name : classType . aliasName || classType . details . name , expected : typeParameters . length , received : typeArgCount , } ) , typeArgs . length > 0 ? typeArgs [ 0 ] . node . parent ! : errorNode ) ; } typeArgs . forEach ( ( typeArg , index ) => { if ( index === variadicTypeParamIndex ) { if ( isClassInstance ( typeArg . type ) && isTupleClass ( typeArg . type ) ) { return ; } if ( isVariadicTypeVar ( typeArg . type ) ) { validateVariadicTypeVarIsUnpacked ( typeArg . type , typeArg . node ) ; return ; } } const typeParam = index < typeParameters . length ? typeParameters [ index ] : undefined ; const isParamSpecTarget = typeParam ?. details . isParamSpec ; validateTypeArg ( typeArg , false , false , true , isParamSpecTarget ) ; } ) ; } const typeArgTypes = [ ] ; const fullTypeParams = ClassType . getTypeParameters ( classType ) ; if ( fullTypeParams . length === 1 && fullTypeParams [ 0 ] . details . isParamSpec && typeArgs ) { if ( typeArgs . every ( ( typeArg ) => ! isEllipsisType ( typeArg . type ) && ! typeArg . typeList && ! isParamSpec ( typeArg . type ) ) ) { if ( typeArgs . length !== 1 || ! isInstantiableClass ( typeArgs [ 0 ] . type ) || ! ClassType . isBuiltIn ( typeArgs [ 0 ] . type , 'Concatenate' ) ) { typeArgs = [ { type : UnknownType . create ( ) , node : typeArgs [ 0 ] . node , typeList : typeArgs , } , ] ; } } else if ( typeArgs . length > 1 ) { const paramSpecTypeArg = typeArgs . find ( ( typeArg ) => isParamSpec ( typeArg . type ) ) ; if ( paramSpecTypeArg ) { addError ( Localizer . Diagnostic . paramSpecContext ( ) , paramSpecTypeArg . node ) ; } const listTypeArg = typeArgs . find ( ( typeArg ) => ! ! typeArg . typeList ) ; if ( listTypeArg ) { addError ( Localizer . Diagnostic . typeArgListNotAllowed ( ) , listTypeArg . node ) ; } } } fullTypeParams . forEach ( ( typeParam , index ) => { if ( typeArgs && index < typeArgs . length ) { if ( typeParam . details . isParamSpec ) { const typeArg = typeArgs [ index ] ; const functionType = FunctionType . createInstantiable ( '' , '' , '' , FunctionTypeFlags . ParamSpecValue ) ; TypeBase . setSpecialForm ( functionType ) ; if ( isEllipsisType ( typeArg . type ) ) { FunctionType . addDefaultParameters ( functionType ) ; functionType . details . flags |= FunctionTypeFlags . SkipArgsKwargsCompatibilityCheck ; typeArgTypes . push ( functionType ) ; return ; } if ( typeArg . typeList ) { typeArg . typeList ! . forEach ( ( paramType , paramIndex ) => { FunctionType . addParameter ( functionType , { category : ParameterCategory . Simple , name : `__p${ paramIndex }` , isNameSynthesized : true , type : convertToInstance ( paramType . type ) , hasDeclaredType : true , } ) ; } ) ; typeArgTypes . push ( functionType ) ; return ; } if ( isInstantiableClass ( typeArg . type ) && ClassType . isBuiltIn ( typeArg . type , 'Concatenate' ) ) { const concatTypeArgs = typeArg . type . typeArguments ; if ( concatTypeArgs && concatTypeArgs . length > 0 ) { concatTypeArgs . forEach ( ( typeArg , index ) => { if ( index === concatTypeArgs . length - 1 ) { if ( isParamSpec ( typeArg ) ) { functionType . details . paramSpec = typeArg ; } } else { FunctionType . addParameter ( functionType , { category : ParameterCategory . Simple , name : `__p${ index }` , isNameSynthesized : true , hasDeclaredType : true , type : typeArg , } ) ; } } ) ; } typeArgTypes . push ( functionType ) ; return ; } } typeArgTypes . push ( convertToInstance ( typeArgs [ index ] . type ) ) ; return ; } typeArgTypes . push ( UnknownType . create ( ) ) ; } ) ; typeArgTypes . forEach ( ( typeArgType , index ) => { if ( index < typeArgCount ) { const diag = new DiagnosticAddendum ( ) ; if ( ! canAssignToTypeVar ( typeParameters [ index ] , typeArgType , diag ) ) { if ( ! isClassInstance ( typeArgType ) || ! ClassType . isPartiallyConstructed ( typeArgType ) ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( typeArgs ! [ index ] . node ) ; addDiagnostic ( fileInfo . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . typeVarAssignmentMismatch ( ) . format ( { type : printType ( typeArgType ) , name : TypeVarType . getReadableName ( typeParameters [ index ] ) , } ) + diag . getString ( ) , typeArgs ! [ index ] . node ) ; } } } } ) ; const specializedClass = ClassType . cloneForSpecialization ( classType , typeArgTypes , typeArgs !== undefined ) ; return specializedClass ; } function getTypeForArgument ( arg ) { if ( arg . type ) { return { type : arg . type } ; } if ( ! arg . valueExpression ) { return { type : UnknownType . create ( ) } ; } return getTypeOfExpression ( arg . valueExpression ) ; } function getTypeForArgumentExpectingType ( arg ) { if ( arg . type ) { return { type : arg . type } ; } return getTypeForExpressionExpectingType ( arg . valueExpression ! ) ; } function getTypeForExpressionExpectingType ( node , allowFinal = false , allowRequired = false ) { let flags = EvaluatorFlags . ExpectingType | EvaluatorFlags . EvaluateStringLiteralAsType | EvaluatorFlags . ParamSpecDisallowed | EvaluatorFlags . TypeVarTupleDisallowed | EvaluatorFlags . ClassVarDisallowed ; const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; if ( fileInfo . isStubFile ) { flags |= EvaluatorFlags . AllowForwardReferences ; } if ( ! allowFinal ) { flags |= EvaluatorFlags . FinalDisallowed ; } if ( allowRequired ) { flags |= EvaluatorFlags . RequiredAllowed ; } return getTypeOfExpression ( node , undefined , flags ) ; } function getBuiltInType ( node , name ) { const scope = ScopeUtils . getScopeForNode ( node ) ; if ( scope ) { const builtInScope = ScopeUtils . getBuiltInScope ( scope ) ; const nameType = builtInScope . lookUpSymbol ( name ) ; if ( nameType ) { return getEffectiveTypeOfSymbol ( nameType ) ; } } return UnknownType . create ( ) ; } function getBuiltInObject ( node , name , typeArguments ? ) { const nameType = getBuiltInType ( node , name ) ; if ( isInstantiableClass ( nameType ) ) { let classType = nameType ; if ( typeArguments ) { classType = ClassType . cloneForSpecialization ( classType , typeArguments , typeArguments !== undefined ) ; } return ClassType . cloneAsInstance ( classType ) ; } return nameType ; } function lookUpSymbolRecursive ( node , name , honorCodeFlow , preferGlobalScope = false ) { const scope = ScopeUtils . getScopeForNode ( node ) ; let symbolWithScope = scope ?. lookUpSymbolRecursive ( name ) ; if ( symbolWithScope && honorCodeFlow ) { const reachableDecls = symbolWithScope . symbol . getDeclarations ( ) . filter ( ( decl ) => { if ( decl . type !== DeclarationType . Alias && decl . type !== DeclarationType . Intrinsic ) { const usageScope = ParseTreeUtils . getExecutionScopeNode ( node ) ; const declNode = decl . type === DeclarationType . Class || decl . type === DeclarationType . Function ? decl . node . name : decl . node ; const declScope = ParseTreeUtils . getExecutionScopeNode ( declNode ) ; if ( usageScope === declScope ) { if ( ! isFlowPathBetweenNodes ( declNode , node ) ) { const flowNode = AnalyzerNodeInfo . getFlowNode ( node ) ; const isReachable = flowNode && codeFlowEngine . isFlowNodeReachable ( flowNode ) ; return ! isReachable ; } } } return true ; } ) ; if ( reachableDecls . length === 0 ) { if ( symbolWithScope . scope . type !== ScopeType . Function && symbolWithScope . scope . parent ) { symbolWithScope = symbolWithScope . scope . parent . lookUpSymbolRecursive ( name , symbolWithScope . isOutsideCallerModule || symbolWithScope . scope . type === ScopeType . Module , symbolWithScope . isBeyondExecutionScope || symbolWithScope . scope . isIndependentlyExecutable ( ) ) ; } else { symbolWithScope = undefined ; } } } if ( symbolWithScope && preferGlobalScope ) { let curSymbolWithScope = symbolWithScope ; while ( curSymbolWithScope . scope . type !== ScopeType . Module && curSymbolWithScope . scope . type !== ScopeType . Builtin && curSymbolWithScope . scope . parent ) { curSymbolWithScope = curSymbolWithScope . scope . parent . lookUpSymbolRecursive ( name , curSymbolWithScope . isOutsideCallerModule , curSymbolWithScope . isBeyondExecutionScope || curSymbolWithScope . scope . isIndependentlyExecutable ( ) ) ; if ( ! curSymbolWithScope ) { break ; } } if ( curSymbolWithScope ?. scope . type === ScopeType . Module || curSymbolWithScope ?. scope . type === ScopeType . Builtin ) { symbolWithScope = curSymbolWithScope ; } } return symbolWithScope ; } function suppressDiagnostics < T > ( node , callback ) { suppressedNodeStack . push ( node ) ; try { return callback ( ) ; } finally { suppressedNodeStack . pop ( ) ; } } function useSpeculativeMode < T > ( speculativeNode , callback , allowCacheRetention = true ) { speculativeTypeTracker . enterSpeculativeContext ( speculativeNode , allowCacheRetention ) ; try { return callback ( ) ; } finally { speculativeTypeTracker . leaveSpeculativeContext ( ) ; } } function disableSpeculativeMode ( callback ) { const stack = speculativeTypeTracker . disableSpeculativeMode ( ) ; try { callback ( ) ; } finally { speculativeTypeTracker . enableSpeculativeMode ( stack ) ; } } function getDeclarationFromFunctionNamedParameter ( type , paramName ) { if ( isFunction ( type ) ) { if ( type . details . declaration ) { const functionDecl = type . details . declaration ; if ( functionDecl . type === DeclarationType . Function ) { const functionNode = functionDecl . node ; const functionScope = AnalyzerNodeInfo . getScope ( functionNode ) ; if ( functionScope ) { const paramSymbol = functionScope . lookUpSymbol ( paramName ) ! ; if ( paramSymbol ) { return paramSymbol . getDeclarations ( ) . find ( ( decl ) => decl . type === DeclarationType . Parameter ) ; } } } } } return undefined ; } function getDeclarationsForNameNode ( node ) { if ( AnalyzerNodeInfo . isCodeUnreachable ( node ) ) { return undefined ; } const declarations = [ ] ; if ( node . parent && node . parent . nodeType === ParseNodeType . ImportFromAs && node . parent . alias && node === node . parent . name ) { const scope = ScopeUtils . getScopeForNode ( node ) ; if ( scope ) { const symbolInScope = scope . lookUpSymbolRecursive ( node . parent . alias . value ) ; if ( symbolInScope ) { const declsForThisImport = symbolInScope . symbol . getDeclarations ( ) . filter ( ( decl ) => { return decl . type === DeclarationType . Alias && decl . node === node . parent ; } ) ; declarations . push ( ... getDeclarationsWithUsesLocalNameRemoved ( declsForThisImport ) ) ; } } } else if ( node . parent && node . parent . nodeType === ParseNodeType . MemberAccess && node === node . parent . memberName ) { let baseType = getType ( node . parent . leftExpression ) ; if ( baseType ) { baseType = makeTopLevelTypeVarsConcrete ( baseType ) ; const memberName = node . parent . memberName . value ; doForEachSubtype ( baseType , ( subtype ) => { let symbol ; subtype = makeTopLevelTypeVarsConcrete ( subtype ) ; if ( isInstantiableClass ( subtype ) ) { let member = lookUpClassMember ( subtype , memberName , ClassMemberLookupFlags . DeclaredTypesOnly ) ; if ( ! member ) { member = lookUpClassMember ( subtype , memberName ) ; } if ( ! member ) { const metaclass = subtype . details . effectiveMetaclass ; if ( metaclass && isInstantiableClass ( metaclass ) ) { member = lookUpClassMember ( metaclass , memberName ) ; } } if ( member ) { symbol = member . symbol ; } } else if ( isClassInstance ( subtype ) ) { let member = lookUpObjectMember ( subtype , memberName , ClassMemberLookupFlags . DeclaredTypesOnly ) ; if ( ! member ) { member = lookUpObjectMember ( subtype , memberName ) ; } if ( member ) { symbol = member . symbol ; } } else if ( isModule ( subtype ) ) { symbol = ModuleType . getField ( subtype , memberName ) ; } if ( symbol ) { const typedDecls = symbol . getTypedDeclarations ( ) ; if ( typedDecls . length > 0 ) { declarations . push ( ... typedDecls ) ; } else { declarations . push ( ... symbol . getDeclarations ( ) ) ; } } } ) ; } } else if ( node . parent && node . parent . nodeType === ParseNodeType . ModuleName ) { const namePartIndex = node . parent . nameParts . findIndex ( ( part ) => part === node ) ; const importInfo = AnalyzerNodeInfo . getImportInfo ( node . parent ) ; if ( namePartIndex >= 0 && importInfo && ! importInfo . isNativeLib && namePartIndex < importInfo . resolvedPaths . length ) { if ( importInfo . resolvedPaths [ namePartIndex ] ) { evaluateTypesForStatement ( node ) ; declarations . push ( createSynthesizedAliasDeclaration ( importInfo . resolvedPaths [ namePartIndex ] ) ) ; } } } else if ( node . parent && node . parent . nodeType === ParseNodeType . Argument && node === node . parent . name ) { const argNode = node . parent ; const paramName = node . value ; if ( argNode . parent && argNode . parent . nodeType === ParseNodeType . Call ) { const baseType = getTypeOfExpression ( argNode . parent . leftExpression , undefined , EvaluatorFlags . DoNotSpecialize ) . type ; if ( baseType ) { if ( isFunction ( baseType ) && baseType . details . declaration ) { const paramDecl = getDeclarationFromFunctionNamedParameter ( baseType , paramName ) ; if ( paramDecl ) { declarations . push ( paramDecl ) ; } } else if ( isOverloadedFunction ( baseType ) ) { baseType . overloads . forEach ( ( f ) => { const paramDecl = getDeclarationFromFunctionNamedParameter ( f , paramName ) ; if ( paramDecl ) { declarations . push ( paramDecl ) ; } } ) ; } else if ( isInstantiableClass ( baseType ) ) { const initMethodType = getTypeFromObjectMember ( argNode . parent . leftExpression , ClassType . cloneAsInstance ( baseType ) , '__init__' , { method : 'get' } , undefined , MemberAccessFlags . SkipObjectBaseClass ) ?. type ; if ( initMethodType && isFunction ( initMethodType ) ) { const paramDecl = getDeclarationFromFunctionNamedParameter ( initMethodType , paramName ) ; if ( paramDecl ) { declarations . push ( paramDecl ) ; } else if ( ClassType . isDataClass ( baseType ) ) { const lookupResults = lookUpClassMember ( baseType , paramName ) ; if ( lookupResults ) { declarations . push ( ... lookupResults . symbol . getDeclarations ( ) ) ; } } } } } } } else { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; const isWithinTypeAnnotation = ParseTreeUtils . isWithinTypeAnnotation ( node , ! isAnnotationEvaluationPostponed ( AnalyzerNodeInfo . getFileInfo ( node ) ) ) ; const allowForwardReferences = isWithinTypeAnnotation || fileInfo . isStubFile ; const symbolWithScope = lookUpSymbolRecursive ( node , node . value , ! allowForwardReferences , isWithinTypeAnnotation ) ; if ( symbolWithScope ) { declarations . push ( ... symbolWithScope . symbol . getDeclarations ( ) ) ; } } return declarations ; } function getTypeForDeclaration ( declaration ) { switch ( declaration . type ) { case DeclarationType . Intrinsic : { if ( declaration . intrinsicType === 'Any' ) { return AnyType . create ( ) ; } if ( declaration . intrinsicType === 'class' ) { const classNode = ParseTreeUtils . getEnclosingClass ( declaration . node ) as ClassNode ; const classTypeInfo = getTypeOfClass ( classNode ) ; return classTypeInfo ? classTypeInfo . classType : undefined ; } const strType = getBuiltInObject ( declaration . node , 'str' ) ; const intType = getBuiltInObject ( declaration . node , 'int' ) ; if ( isClassInstance ( intType ) && isClassInstance ( strType ) ) { if ( declaration . intrinsicType === 'str' ) { return strType ; } if ( declaration . intrinsicType === 'str | None' ) { return combineTypes ( [ strType , NoneType . createInstance ( ) ] ) ; } if ( declaration . intrinsicType === 'int' ) { return intType ; } if ( declaration . intrinsicType === 'Iterable[str]' ) { const iterableType = getBuiltInType ( declaration . node , 'Iterable' ) ; if ( isInstantiableClass ( iterableType ) ) { return ClassType . cloneAsInstance ( ClassType . cloneForSpecialization ( iterableType , [ strType ] , true ) ) ; } } if ( declaration . intrinsicType === 'Dict[str, Any]' ) { const dictType = getBuiltInType ( declaration . node , 'dict' ) ; if ( isInstantiableClass ( dictType ) ) { return ClassType . cloneAsInstance ( ClassType . cloneForSpecialization ( dictType , [ strType , AnyType . create ( ) ] , true ) ) ; } } } return UnknownType . create ( ) ; } case DeclarationType . Class : { const classTypeInfo = getTypeOfClass ( declaration . node ) ; return classTypeInfo ? classTypeInfo . decoratedType : undefined ; } case DeclarationType . SpecialBuiltInClass : { return getTypeOfAnnotation ( declaration . node . typeAnnotation ) ; } case DeclarationType . Function : { const functionTypeInfo = getTypeOfFunction ( declaration . node ) ; return functionTypeInfo ? functionTypeInfo . decoratedType : undefined ; } case DeclarationType . Parameter : { let typeAnnotationNode = declaration . node . typeAnnotation || declaration . node . typeAnnotationComment ; if ( ! typeAnnotationNode ) { if ( declaration . node . parent ?. nodeType === ParseNodeType . Function ) { const functionNode = declaration . node . parent ; if ( functionNode . functionAnnotationComment && ! functionNode . functionAnnotationComment . isParamListEllipsis ) { const paramIndex = functionNode . parameters . findIndex ( ( param ) => param === declaration . node ) ; typeAnnotationNode = getTypeAnnotationForParameter ( functionNode , paramIndex ) ; } } } if ( typeAnnotationNode ) { const declaredType = getTypeOfAnnotation ( typeAnnotationNode , { associateTypeVarsWithScope : true , allowTypeVarTuple : declaration . node . category === ParameterCategory . VarArgList , disallowRecursiveTypeAlias : true , } ) ; return transformVariadicParamType ( declaration . node , declaration . node . category , adjustParameterAnnotatedType ( declaration . node , declaredType ) ) ; } return undefined ; } case DeclarationType . Variable : { const typeAnnotationNode = declaration . typeAnnotationNode ; if ( typeAnnotationNode ) { const typeAliasNode = isDeclaredTypeAlias ( typeAnnotationNode ) ? ParseTreeUtils . getTypeAnnotationNode ( typeAnnotationNode ) : undefined ; let declaredType ; if ( declaration . isRuntimeTypeExpression ) { declaredType = convertToInstance ( getTypeForExpressionExpectingType ( typeAnnotationNode , true , true ) . type ) ; } else { const declNode = declaration . isDefinedByMemberAccess && declaration . node . parent ?. nodeType === ParseNodeType . MemberAccess ? declaration . node . parent : declaration . node ; declaredType = getTypeOfAnnotation ( typeAnnotationNode , { isVariableAnnotation : true , allowClassVar : ParseTreeUtils . isClassVarAllowedForAssignmentTarget ( declNode ) , allowFinal : ParseTreeUtils . isFinalAllowedForAssignmentTarget ( declNode ) , } ) ; } if ( declaredType ) { if ( declaration . node . nodeType === ParseNodeType . Name ) { declaredType = transformTypeForPossibleEnumClass ( declaration . node , ( ) => declaredType ) || declaredType ; } if ( typeAliasNode && typeAliasNode . valueExpression . nodeType === ParseNodeType . Name ) { declaredType = transformTypeForTypeAlias ( declaredType , typeAliasNode . valueExpression , declaration . node ) ; } return declaredType ; } } return undefined ; } case DeclarationType . Alias : { return undefined ; } } } function getInferredTypeOfDeclaration ( decl ) { const resolvedDecl = resolveAliasDeclaration ( decl , true , AnalyzerNodeInfo . getFileInfo ( decl . node ) . isStubFile ) ; if ( ! resolvedDecl ) { return evaluatorOptions . evaluateUnknownImportsAsAny ? AnyType . create ( ) : UnknownType . create ( ) ; } function applyLoaderActionsToModuleType ( moduleType , loaderActions , importLookup ) { if ( loaderActions . path && loaderActions . loadSymbolsFromPath ) { const lookupResults = importLookup ( loaderActions . path ) ; if ( lookupResults ) { moduleType . fields = lookupResults . symbolTable ; moduleType . docString = lookupResults . docString ; } else { return evaluatorOptions . evaluateUnknownImportsAsAny ? AnyType . create ( ) : UnknownType . create ( ) ; } } if ( loaderActions . implicitImports ) { loaderActions . implicitImports . forEach ( ( implicitImport , name ) => { const moduleName = moduleType . moduleName ? moduleType . moduleName + '.' + name : '' ; const importedModuleType = ModuleType . create ( moduleName , implicitImport . path ) ; const symbolType = applyLoaderActionsToModuleType ( importedModuleType , implicitImport , importLookup ) ; const importedModuleSymbol = Symbol . createWithType ( SymbolFlags . None , symbolType ) ; moduleType . loaderFields . set ( name , importedModuleSymbol ) ; } ) ; } return moduleType ; } if ( resolvedDecl . type === DeclarationType . Alias ) { let moduleName = resolvedDecl . moduleName ; if ( decl . type === DeclarationType . Alias ) { if ( decl . symbolName ) { moduleName += '.' + decl . symbolName ; } if ( moduleName . startsWith ( '.' ) ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( decl . node ) ; const nameParts = fileInfo . moduleName . split ( '.' ) ; moduleName = moduleName . substr ( 1 ) ; while ( moduleName . startsWith ( '.' ) && nameParts . length > 0 ) { moduleName = moduleName . substr ( 1 ) ; nameParts . pop ( ) ; } moduleName = nameParts . join ( '.' ) + '.' + moduleName ; } } const moduleType = ModuleType . create ( moduleName , resolvedDecl . path ) ; if ( resolvedDecl . symbolName && resolvedDecl . submoduleFallback ) { return applyLoaderActionsToModuleType ( moduleType , resolvedDecl . submoduleFallback , importLookup ) ; } else { return applyLoaderActionsToModuleType ( moduleType , resolvedDecl , importLookup ) ; } } const declaredType = getTypeForDeclaration ( resolvedDecl ) ; if ( declaredType ) { return declaredType ; } const fileInfo = AnalyzerNodeInfo . getFileInfo ( resolvedDecl . node ) ; let isSpeculativeTypeAliasFromPyTypedFile = false ; if ( fileInfo . isInPyTypedPackage && ! fileInfo . isStubFile && evaluatorOptions . disableInferenceForPyTypedSources ) { if ( resolvedDecl . type !== DeclarationType . Variable ) { return UnknownType . create ( ) ; } const enclosingClass = ParseTreeUtils . getEnclosingClass ( resolvedDecl . node , true ) ; let isEnumValue = false ; if ( enclosingClass ) { const classTypeInfo = getTypeOfClass ( enclosingClass ) ; if ( classTypeInfo && ClassType . isEnumClass ( classTypeInfo . classType ) ) { isEnumValue = true ; } } if ( ! resolvedDecl . isFinal && ! resolvedDecl . isConstant && ! isEnumValue ) { if ( ! resolvedDecl . typeAliasName ) { return UnknownType . create ( ) ; } else if ( ! resolvedDecl . typeAliasAnnotation ) { isSpeculativeTypeAliasFromPyTypedFile = true ; } } } if ( resolvedDecl . type === DeclarationType . Parameter ) { return evaluateTypeForSubnode ( resolvedDecl . node . name ! , ( ) => { evaluateTypeOfParameter ( resolvedDecl . node ) ; } ) ?. type ; } if ( resolvedDecl . type === DeclarationType . Variable && resolvedDecl . inferredTypeSource ) { const typeSource = resolvedDecl . typeAliasName && resolvedDecl . inferredTypeSource . parent ? resolvedDecl . inferredTypeSource . parent : resolvedDecl . inferredTypeSource ; let inferredType = evaluateTypeForSubnode ( resolvedDecl . node , ( ) => { evaluateTypesForStatement ( typeSource ) ; } ) ?. type ; if ( inferredType && resolvedDecl . node . nodeType === ParseNodeType . Name ) { const enumMemberType = transformTypeForPossibleEnumClass ( resolvedDecl . node , ( ) => { return ( evaluateTypeForSubnode ( resolvedDecl . inferredTypeSource ! , ( ) => { evaluateTypesForStatement ( resolvedDecl . inferredTypeSource ! ) ; } ) ?. type || UnknownType . create ( ) ) ; } ) ; if ( enumMemberType ) { inferredType = enumMemberType ; } } if ( inferredType && resolvedDecl . typeAliasName ) { if ( TypeBase . isInstantiable ( inferredType ) && ! isAnyOrUnknown ( inferredType ) ) { inferredType = transformTypeForTypeAlias ( inferredType , resolvedDecl . typeAliasName , resolvedDecl . node ) ; } else if ( isSpeculativeTypeAliasFromPyTypedFile ) { return UnknownType . create ( ) ; } } return inferredType ; } return undefined ; } function resolveAliasDeclaration ( declaration , resolveLocalNames , allowExternallyHiddenAccess = false ) { return DeclarationUtils . resolveAliasDeclaration ( importLookup , declaration , resolveLocalNames , allowExternallyHiddenAccess ) ?. declaration ; } function resolveAliasDeclarationWithInfo ( declaration , resolveLocalNames , allowExternallyHiddenAccess = false ) { return DeclarationUtils . resolveAliasDeclaration ( importLookup , declaration , resolveLocalNames , allowExternallyHiddenAccess ) ; } function getEffectiveTypeOfSymbol ( symbol ) { return getEffectiveTypeOfSymbolForUsage ( symbol ) . type ; } function getEffectiveTypeOfSymbolForUsage ( symbol , usageNode ? , useLastDecl = false ) { if ( symbol . hasTypedDeclarations ( ) ) { const declaredType = getDeclaredTypeOfSymbol ( symbol ) ; return { type : declaredType || UnknownType . create ( ) , isIncomplete : false , includesVariableDecl : symbol . getTypedDeclarations ( ) . some ( ( decl ) => decl . type === DeclarationType . Variable ) , isRecursiveDefinition : ! declaredType , } ; } let cacheEntries = effectiveTypeCache . get ( symbol . id ) ; const usageNodeId = usageNode ? usageNode . id : undefined ; if ( cacheEntries ) { for ( const entry of cacheEntries ) { if ( entry . usageNodeId === usageNodeId && entry . useLastDecl === useLastDecl ) { return entry . result ; } } } const typesToCombine = [ ] ; const decls = symbol . getDeclarations ( ) ; const isFinalVar = isFinalVariable ( symbol ) ; let isIncomplete = false ; let includesVariableDecl = false ; let includesSpeculativeResult = false ; decls . forEach ( ( decl , index ) => { let considerDecl = ! useLastDecl || index === decls . length - 1 ; if ( usageNode !== undefined ) { if ( decl . type !== DeclarationType . Alias ) { const usageScope = ParseTreeUtils . getExecutionScopeNode ( usageNode ) ; const declScope = ParseTreeUtils . getExecutionScopeNode ( decl . node ) ; if ( usageScope === declScope ) { if ( ! isFlowPathBetweenNodes ( decl . node , usageNode ) ) { considerDecl = false ; } } } } if ( considerDecl ) { const isTypeAlias = isExplicitTypeAliasDeclaration ( decl ) || isPossibleTypeAliasDeclaration ( decl ) ; if ( isTypeAlias && decl . type === DeclarationType . Variable && decl . inferredTypeSource ?. parent ?. nodeType === ParseNodeType . Assignment ) { evaluateTypesForAssignmentStatement ( decl . inferredTypeSource . parent ) ; if ( decl . typeAliasAnnotation ) { getTypeOfAnnotation ( decl . typeAliasAnnotation , { isVariableAnnotation : true , allowFinal : ParseTreeUtils . isFinalAllowedForAssignmentTarget ( decl . node ) , allowClassVar : ParseTreeUtils . isClassVarAllowedForAssignmentTarget ( decl . node ) , } ) ; } } if ( pushSymbolResolution ( symbol , decl ) ) { try { let type = getInferredTypeOfDeclaration ( decl ) ; if ( ! popSymbolResolution ( symbol ) ) { isIncomplete = true ; } if ( type ) { if ( decl . type === DeclarationType . Variable ) { includesVariableDecl = true ; let isConstant = decl . type === DeclarationType . Variable && ! ! decl . isConstant ; if ( isClassInstance ( type ) && ClassType . isEnumClass ( type ) && isDeclInEnumClass ( decl ) ) { isConstant = true ; } if ( TypeBase . isInstance ( type ) && ! isTypeAlias && ! isConstant && ! isFinalVar ) { type = stripLiteralValue ( type ) ; } } typesToCombine . push ( type ) ; if ( speculativeTypeTracker . isSpeculative ( decl . node ) ) { includesSpeculativeResult = true ; } } else { isIncomplete = true ; } } catch ( e ) { popSymbolResolution ( symbol ) ; throw e ; } } else { isIncomplete = true ; } } } ) ; if ( typesToCombine . length > 0 ) { const result = { type : combineTypes ( typesToCombine ) , isIncomplete : false , includesVariableDecl , isRecursiveDefinition : false , } ; if ( ! includesSpeculativeResult ) { if ( ! cacheEntries ) { cacheEntries = [ ] ; effectiveTypeCache . set ( symbol . id , cacheEntries ) ; } cacheEntries . push ( { usageNodeId , useLastDecl , result , } ) ; } return result ; } return { type : UnboundType . create ( ) , isIncomplete , includesVariableDecl , isRecursiveDefinition : false , } ; } function getDeclaredTypeOfSymbol ( symbol ) { const synthesizedType = symbol . getSynthesizedType ( ) ; if ( synthesizedType ) { return synthesizedType ; } const typedDecls = symbol . getTypedDeclarations ( ) ; if ( typedDecls . length === 0 ) { return undefined ; } let declIndex = typedDecls . length - 1 ; while ( declIndex >= 0 ) { const decl = typedDecls [ declIndex ] ; const partialType = getSymbolResolutionPartialType ( symbol , decl ) ; if ( partialType ) { return partialType ; } if ( getIndexOfSymbolResolution ( symbol , decl ) < 0 ) { if ( pushSymbolResolution ( symbol , decl ) ) { try { const type = getTypeForDeclaration ( decl ) ; if ( popSymbolResolution ( symbol ) || decl . type === DeclarationType . Class ) { return type ; } } catch ( e ) { popSymbolResolution ( symbol ) ; throw e ; } } } declIndex -- ; } return undefined ; } function isDeclInEnumClass ( decl ) { const classNode = ParseTreeUtils . getEnclosingClass ( decl . node , true ) ; if ( ! classNode ) { return false ; } const classInfo = getTypeOfClass ( classNode ) ; if ( ! classInfo ) { return false ; } return ClassType . isEnumClass ( classInfo . classType ) ; } function inferReturnTypeIfNecessary ( type ) { if ( isFunction ( type ) ) { getFunctionEffectiveReturnType ( type ) ; } else if ( isOverloadedFunction ( type ) ) { type . overloads . forEach ( ( overload ) => { getFunctionEffectiveReturnType ( overload ) ; } ) ; } } function getFunctionEffectiveReturnType ( type , args ? , inferTypeIfNeeded = true ) { const specializedReturnType = FunctionType . getSpecializedReturnType ( type ) ; if ( specializedReturnType ) { return specializedReturnType ; } if ( inferTypeIfNeeded ) { return getFunctionInferredReturnType ( type , args ) ; } return UnknownType . create ( ) ; } function getFunctionInferredReturnType ( type , args ? ) { let returnType ; if ( FunctionType . isStubDefinition ( type ) || FunctionType . isPyTypedDefinition ( type ) ) { return UnknownType . create ( ) ; } if ( type . inferredReturnType ) { returnType = type . inferredReturnType ; } else { if ( FunctionType . isInstanceMethod ( type ) && type . details . name === '__init__' ) { returnType = NoneType . createInstance ( ) ; } else if ( type . details . declaration ) { const functionNode = type . details . declaration . node ; if ( evaluatorOptions . analyzeUnannotatedFunctions ) { const codeFlowComplexity = AnalyzerNodeInfo . getCodeFlowComplexity ( functionNode ) ; const parametersAreAnnotated = type . details . parameters . length <= 1 || type . details . parameters . some ( ( param ) => param . hasDeclaredType ) ; if ( parametersAreAnnotated || codeFlowComplexity < maxReturnTypeInferenceCodeFlowComplexity ) { disableSpeculativeMode ( ( ) => { returnType = inferFunctionReturnType ( functionNode , FunctionType . isAbstractMethod ( type ) ) ; } ) ; if ( returnType && FunctionType . isWrapReturnTypeInAwait ( type ) ) { returnType = createAwaitableReturnType ( functionNode , returnType , ! ! type . details . declaration ?. isGenerator ) ; } } } } if ( ! returnType ) { returnType = UnknownType . create ( ) ; } type . inferredReturnType = returnType ; } if ( evaluatorOptions . analyzeUnannotatedFunctions && isPartlyUnknown ( returnType ) && FunctionType . hasUnannotatedParams ( type ) && ! FunctionType . isStubDefinition ( type ) && ! FunctionType . isPyTypedDefinition ( type ) && args ) { const contextualReturnType = getFunctionInferredReturnTypeUsingArguments ( type , args ) ; if ( contextualReturnType ) { returnType = removeNoReturnFromUnion ( contextualReturnType ) ; } } return returnType ; } function getFunctionInferredReturnTypeUsingArguments ( type , args ) { let contextualReturnType ; if ( ! type . details . declaration ) { return undefined ; } const functionNode = type . details . declaration . node ; if ( args . some ( ( arg ) => ! arg . paramName ) ) { return undefined ; } if ( returnTypeInferenceContextStack . some ( ( context ) => context . functionNode === functionNode ) ) { return undefined ; } const functionType = getTypeOfFunction ( functionNode ) ; if ( ! functionType ) { return undefined ; } if ( args . length > maxReturnTypeInferenceArgumentCount ) { return undefined ; } if ( returnTypeInferenceContextStack . length >= maxReturnTypeInferenceStackSize ) { return undefined ; } suppressDiagnostics ( functionNode , ( ) => { const prevTypeCache = returnTypeInferenceTypeCache ; returnTypeInferenceContextStack . push ( { functionNode , codeFlowAnalyzer : codeFlowEngine . createCodeFlowAnalyzer ( ) , } ) ; try { returnTypeInferenceTypeCache = new Map < number , CachedType > ( ) ; let allArgTypesAreUnknown = true ; functionNode . parameters . forEach ( ( param , index ) => { if ( param . name ) { let paramType ; const arg = args . find ( ( arg ) => param . name ! . value === arg . paramName ) ; if ( arg && arg . argument . valueExpression ) { paramType = getTypeOfExpression ( arg . argument . valueExpression ) . type ; if ( ! isUnknown ( paramType ) ) { allArgTypesAreUnknown = false ; } } else if ( param . defaultValue ) { paramType = getTypeOfExpression ( param . defaultValue ) . type ; if ( ! isUnknown ( paramType ) ) { allArgTypesAreUnknown = false ; } } else if ( index === 0 ) { if ( FunctionType . isInstanceMethod ( functionType . functionType ) || FunctionType . isClassMethod ( functionType . functionType ) ) { if ( functionType . functionType . details . parameters . length > 0 ) { if ( functionNode . parameters [ 0 ] . name ) { paramType = functionType . functionType . details . parameters [ 0 ] . type ; } } } } if ( ! paramType ) { paramType = UnknownType . create ( ) ; } writeTypeCache ( param . name , paramType , EvaluatorFlags . None , false ) ; } } ) ; if ( ! allArgTypesAreUnknown ) { contextualReturnType = inferFunctionReturnType ( functionNode , FunctionType . isAbstractMethod ( type ) ) ; } } finally { returnTypeInferenceContextStack . pop ( ) ; returnTypeInferenceTypeCache = prevTypeCache ; } } ) ; if ( contextualReturnType ) { contextualReturnType = removeUnbound ( contextualReturnType ) ; if ( FunctionType . isWrapReturnTypeInAwait ( type ) && ! isNoReturnType ( contextualReturnType ) ) { contextualReturnType = createAwaitableReturnType ( functionNode , contextualReturnType , ! ! type . details . declaration ?. isGenerator ) ; } return contextualReturnType ; } return undefined ; } function getFunctionDeclaredReturnType ( node ) { const functionTypeInfo = getTypeOfFunction ( node ) ! ; if ( ! functionTypeInfo ) { return AnyType . create ( ) ; } if ( FunctionType . isAbstractMethod ( functionTypeInfo . functionType ) ) { return AnyType . create ( ) ; } if ( FunctionType . isGenerator ( functionTypeInfo . functionType ) ) { return getDeclaredGeneratorReturnType ( functionTypeInfo . functionType ) ; } return functionTypeInfo . functionType . details . declaredReturnType ; } function getTypeOfMember ( member ) { if ( isInstantiableClass ( member . classType ) ) { return partiallySpecializeType ( getEffectiveTypeOfSymbol ( member . symbol ) , member . classType ) ; } return UnknownType . create ( ) ; } function getTypeOfMemberInternal ( node , member , selfClass ) { if ( isInstantiableClass ( member . classType ) ) { const typeResult = getEffectiveTypeOfSymbolForUsage ( member . symbol ) ; if ( typeResult ) { inferReturnTypeIfNecessary ( typeResult . type ) ; return { node , type : partiallySpecializeType ( typeResult . type , member . classType , selfClass ) , isIncomplete : ! ! typeResult . isIncomplete , } ; } } return undefined ; } function canAssignClassToProtocol ( destType , srcType , diag , typeVarMap , flags , treatSourceAsInstantiable , recursionCount ) { if ( recursionCount > maxTypeRecursionCount ) { return true ; } const destClassFields = destType . details . fields ; if ( ClassType . isSameGenericClass ( srcType , destType ) && ! treatSourceAsInstantiable ) { if ( isTypeSame ( srcType , destType , true , undefined , recursionCount + 1 ) ) { return true ; } return verifyTypeArgumentsAssignable ( destType , srcType , diag , typeVarMap , flags , recursionCount + 1 ) ; } const genericDestType = ClassType . cloneForSpecialization ( destType , undefined , false ) ; const genericDestTypeVarMap = new TypeVarMap ( getTypeVarScopeId ( destType ) ) ; const selfTypeVarMap = new TypeVarMap ( getTypeVarScopeId ( destType ) ) ; populateTypeVarMapForSelfType ( selfTypeVarMap , destType , srcType ) ; if ( ClassType . isTypedDictClass ( srcType ) ) { if ( typedDictClassType && isInstantiableClass ( typedDictClassType ) ) { srcType = typedDictClassType ; } } let typesAreConsistent = true ; const srcClassTypeVarMap = buildTypeVarMapFromSpecializedClass ( srcType ) ; destClassFields . forEach ( ( symbol , name ) => { if ( symbol . isClassMember ( ) && ! symbol . isIgnoredForProtocolMatch ( ) ) { let isMemberFromMetaclass = false ; let srcMemberInfo ; if ( treatSourceAsInstantiable && srcType . details . effectiveMetaclass && isInstantiableClass ( srcType . details . effectiveMetaclass ) ) { srcMemberInfo = lookUpClassMember ( srcType . details . effectiveMetaclass , name ) ; if ( srcMemberInfo ) { srcClassTypeVarMap . addSolveForScope ( getTypeVarScopeId ( srcType . details . effectiveMetaclass ) ) ; isMemberFromMetaclass = true ; } } if ( ! srcMemberInfo ) { srcMemberInfo = lookUpClassMember ( srcType , name ) ; } if ( ! srcMemberInfo ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . protocolMemberMissing ( ) . format ( { name } ) ) ; } typesAreConsistent = false ; } else { let destMemberType = getDeclaredTypeOfSymbol ( symbol ) ; if ( destMemberType ) { let srcMemberType = isInstantiableClass ( srcMemberInfo . classType ) ? partiallySpecializeType ( getEffectiveTypeOfSymbol ( srcMemberInfo . symbol ) , srcMemberInfo . classType , srcType ) : UnknownType . create ( ) ; if ( isFunction ( srcMemberType ) || isOverloadedFunction ( srcMemberType ) ) { if ( isMemberFromMetaclass ) { const boundSrcFunction = bindFunctionToClassOrObject ( srcType , srcMemberType , undefined , undefined , recursionCount + 1 , false , srcType ) ; if ( boundSrcFunction ) { srcMemberType = removeParamSpecVariadicsFromSignature ( boundSrcFunction ) ; } if ( isFunction ( destMemberType ) || isOverloadedFunction ( destMemberType ) ) { const boundDeclaredType = bindFunctionToClassOrObject ( srcType , destMemberType , undefined , undefined , recursionCount + 1 , false , srcType ) ; if ( boundDeclaredType ) { destMemberType = removeParamSpecVariadicsFromSignature ( boundDeclaredType ) ; } } } else if ( isInstantiableClass ( srcMemberInfo . classType ) ) { destMemberType = applySolvedTypeVars ( destMemberType , selfTypeVarMap ) ; const boundSrcFunction = bindFunctionToClassOrObject ( treatSourceAsInstantiable ? srcType : ClassType . cloneAsInstance ( srcType ) , srcMemberType , srcMemberInfo . classType , undefined , recursionCount + 1 ) ; if ( boundSrcFunction ) { srcMemberType = removeParamSpecVariadicsFromSignature ( boundSrcFunction ) ; } if ( isFunction ( destMemberType ) || isOverloadedFunction ( destMemberType ) ) { const boundDeclaredType = bindFunctionToClassOrObject ( ClassType . cloneAsInstance ( srcType ) , destMemberType , srcMemberInfo . classType , undefined , recursionCount + 1 ) ; if ( boundDeclaredType ) { destMemberType = removeParamSpecVariadicsFromSignature ( boundDeclaredType ) ; } } } } else { destMemberType = applySolvedTypeVars ( destMemberType , selfTypeVarMap ) ; } const subDiag = diag ?. createAddendum ( ) ; if ( isClassInstance ( destMemberType ) && ClassType . isPropertyClass ( destMemberType ) ) { if ( isClassInstance ( srcMemberType ) && ClassType . isPropertyClass ( srcMemberType ) && ! treatSourceAsInstantiable ) { if ( ! canAssignProperty ( ClassType . cloneAsInstantiable ( destMemberType ) , ClassType . cloneAsInstantiable ( srcMemberType ) , srcType , subDiag ?. createAddendum ( ) , genericDestTypeVarMap , recursionCount + 1 ) ) { if ( subDiag ) { subDiag . addMessage ( Localizer . DiagnosticAddendum . memberTypeMismatch ( ) . format ( { name } ) ) ; } typesAreConsistent = false ; } } else { const getterType = getGetterTypeFromProperty ( destMemberType , true ) ; if ( ! getterType || ! canAssignType ( getterType , srcMemberType , subDiag ?. createAddendum ( ) , genericDestTypeVarMap , CanAssignFlags . Default , recursionCount + 1 ) ) { if ( subDiag ) { subDiag . addMessage ( Localizer . DiagnosticAddendum . memberTypeMismatch ( ) . format ( { name } ) ) ; } typesAreConsistent = false ; } } } else if ( ! canAssignType ( destMemberType , srcMemberType , subDiag ?. createAddendum ( ) , genericDestTypeVarMap , CanAssignFlags . Default , recursionCount + 1 ) ) { if ( subDiag ) { subDiag . addMessage ( Localizer . DiagnosticAddendum . memberTypeMismatch ( ) . format ( { name } ) ) ; } typesAreConsistent = false ; } const isDestFinal = symbol . getTypedDeclarations ( ) . some ( ( decl ) => decl . type === DeclarationType . Variable && ! ! decl . isFinal ) ; const isSrcFinal = srcMemberInfo . symbol . getTypedDeclarations ( ) . some ( ( decl ) => decl . type === DeclarationType . Variable && ! ! decl . isFinal ) ; if ( isDestFinal !== isSrcFinal ) { if ( isDestFinal ) { if ( subDiag ) { subDiag . addMessage ( Localizer . DiagnosticAddendum . memberIsFinalInProtocol ( ) . format ( { name } ) ) ; } } else { if ( subDiag ) { subDiag . addMessage ( Localizer . DiagnosticAddendum . memberIsNotFinalInProtocol ( ) . format ( { name } ) ) ; } } typesAreConsistent = false ; } } if ( symbol . isClassVar ( ) && ! srcMemberInfo . symbol . isClassMember ( ) ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . protocolMemberClassVar ( ) . format ( { name } ) ) ; } typesAreConsistent = false ; } } } } ) ; destType . details . baseClasses . forEach ( ( baseClass ) => { if ( isInstantiableClass ( baseClass ) && ! ClassType . isBuiltIn ( baseClass , 'object' ) && ! ClassType . isBuiltIn ( baseClass , 'Protocol' ) ) { const specializedBaseClass = specializeForBaseClass ( destType , baseClass ) ; if ( ! canAssignClassToProtocol ( specializedBaseClass , srcType , diag ?. createAddendum ( ) , typeVarMap , flags , treatSourceAsInstantiable , recursionCount + 1 ) ) { typesAreConsistent = false ; } } } ) ; if ( typesAreConsistent && destType . details . typeParameters . length > 0 && destType . typeArguments ) { const specializedDestProtocol = applySolvedTypeVars ( genericDestType , genericDestTypeVarMap ) as ClassType ; if ( ! verifyTypeArgumentsAssignable ( destType , specializedDestProtocol , diag , typeVarMap , flags , recursionCount + 1 ) ) { typesAreConsistent = false ; } } return typesAreConsistent ; } function canAssignModuleToProtocol ( destType , srcType , diag , typeVarMap , flags , recursionCount ) { if ( recursionCount > maxTypeRecursionCount ) { return true ; } let typesAreConsistent = true ; const destClassFields = destType . details . fields ; const genericDestType = ClassType . cloneForSpecialization ( destType , undefined , false ) ; const genericDestTypeVarMap = new TypeVarMap ( getTypeVarScopeId ( destType ) ) ; destClassFields . forEach ( ( symbol , name ) => { if ( symbol . isClassMember ( ) && ! symbol . isIgnoredForProtocolMatch ( ) ) { const memberSymbol = srcType . fields . get ( name ) ; if ( ! memberSymbol ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . protocolMemberMissing ( ) . format ( { name } ) ) ; } typesAreConsistent = false ; } else { let declaredType = getDeclaredTypeOfSymbol ( symbol ) ; if ( declaredType ) { const srcMemberType = getEffectiveTypeOfSymbol ( memberSymbol ) ; if ( isFunction ( srcMemberType ) || isOverloadedFunction ( srcMemberType ) ) { if ( isFunction ( declaredType ) || isOverloadedFunction ( declaredType ) ) { const boundDeclaredType = bindFunctionToClassOrObject ( ClassType . cloneAsInstance ( destType ) , declaredType , destType , undefined , recursionCount + 1 ) ; if ( boundDeclaredType ) { declaredType = boundDeclaredType ; } } } const subDiag = diag ?. createAddendum ( ) ; if ( ! canAssignType ( declaredType , srcMemberType , subDiag ?. createAddendum ( ) , genericDestTypeVarMap , CanAssignFlags . Default , recursionCount + 1 ) ) { if ( subDiag ) { subDiag . addMessage ( Localizer . DiagnosticAddendum . memberTypeMismatch ( ) . format ( { name } ) ) ; } typesAreConsistent = false ; } } } } } ) ; destType . details . baseClasses . forEach ( ( baseClass ) => { if ( isInstantiableClass ( baseClass ) && ! ClassType . isBuiltIn ( baseClass , 'object' ) && ! ClassType . isBuiltIn ( baseClass , 'Protocol' ) ) { const specializedBaseClass = specializeForBaseClass ( destType , baseClass ) ; if ( ! canAssignModuleToProtocol ( specializedBaseClass , srcType , diag ?. createAddendum ( ) , typeVarMap , flags , recursionCount + 1 ) ) { typesAreConsistent = false ; } } } ) ; if ( typesAreConsistent && destType . details . typeParameters . length > 0 && destType . typeArguments ) { const specializedSrcProtocol = applySolvedTypeVars ( genericDestType , genericDestTypeVarMap ) as ClassType ; if ( ! verifyTypeArgumentsAssignable ( destType , specializedSrcProtocol , diag , typeVarMap , flags , recursionCount ) ) { typesAreConsistent = false ; } } return typesAreConsistent ; } function canAssignProperty ( destPropertyType , srcPropertyType , srcClass , diag , typeVarMap ? , recursionCount = 0 ) { const objectToBind = ClassType . cloneAsInstance ( srcClass ) ; let isAssignable = true ; const accessors = [ { name : 'fget' , missingDiagMsg : Localizer . DiagnosticAddendum . missingGetter , incompatibleDiagMsg : Localizer . DiagnosticAddendum . incompatibleGetter , } , { name : 'fset' , missingDiagMsg : Localizer . DiagnosticAddendum . missingSetter , incompatibleDiagMsg : Localizer . DiagnosticAddendum . incompatibleSetter , } , { name : 'fdel' , missingDiagMsg : Localizer . DiagnosticAddendum . missingDeleter , incompatibleDiagMsg : Localizer . DiagnosticAddendum . incompatibleDeleter , } , ] ; accessors . forEach ( ( accessorInfo ) => { const destAccessSymbol = destPropertyType . details . fields . get ( accessorInfo . name ) ; const destAccessType = destAccessSymbol ? getDeclaredTypeOfSymbol ( destAccessSymbol ) : undefined ; if ( destAccessType && isFunction ( destAccessType ) ) { const srcAccessSymbol = srcPropertyType . details . fields . get ( accessorInfo . name ) ; const srcAccessType = srcAccessSymbol ? getDeclaredTypeOfSymbol ( srcAccessSymbol ) : undefined ; if ( ! srcAccessType || ! isFunction ( srcAccessType ) ) { if ( diag ) { diag . addMessage ( accessorInfo . missingDiagMsg ( ) ) ; } isAssignable = false ; return ; } const boundDestAccessType = bindFunctionToClassOrObject ( objectToBind , destAccessType , undefined , undefined , recursionCount + 1 ) ; const boundSrcAccessType = bindFunctionToClassOrObject ( objectToBind , srcAccessType , undefined , undefined , recursionCount + 1 ) ; if ( ! boundDestAccessType || ! boundSrcAccessType || ! canAssignType ( boundDestAccessType , boundSrcAccessType , diag ?. createAddendum ( ) , typeVarMap , CanAssignFlags . Default , recursionCount + 1 ) ) { if ( diag ) { diag . addMessage ( 'getter type is incompatible' ) ; } isAssignable = false ; return ; } } } ) ; return isAssignable ; } function canAssignProtocolClassToSelf ( destType , srcType , recursionCount = 0 ) { assert ( ClassType . isProtocolClass ( destType ) ) ; assert ( ClassType . isProtocolClass ( srcType ) ) ; assert ( ClassType . isSameGenericClass ( destType , srcType ) ) ; assert ( destType . details . typeParameters . length > 0 ) ; const diag = new DiagnosticAddendum ( ) ; const typeVarMap = new TypeVarMap ( ) ; let isAssignable = true ; destType . details . fields . forEach ( ( symbol , name ) => { if ( isAssignable && symbol . isClassMember ( ) && ! symbol . isIgnoredForProtocolMatch ( ) ) { const memberInfo = lookUpClassMember ( srcType , name ) ; assert ( memberInfo !== undefined ) ; let destMemberType = getDeclaredTypeOfSymbol ( symbol ) ; if ( destMemberType ) { const srcMemberType = getTypeOfMember ( memberInfo ! ) ; destMemberType = partiallySpecializeType ( destMemberType , destType ) ; if ( isClassInstance ( destMemberType ) && ClassType . isPropertyClass ( destMemberType ) && isClassInstance ( srcMemberType ) && ClassType . isPropertyClass ( srcMemberType ) ) { if ( ! canAssignProperty ( ClassType . cloneAsInstantiable ( destMemberType ) , ClassType . cloneAsInstantiable ( srcMemberType ) , srcType , diag , typeVarMap , recursionCount + 1 ) ) { isAssignable = false ; } } else { const primaryDecl = symbol . getDeclarations ( ) [ 0 ] ; const flags = primaryDecl ?. type === DeclarationType . Variable && ! primaryDecl . isFinal ? CanAssignFlags . EnforceInvariance : CanAssignFlags . Default ; if ( ! canAssignType ( destMemberType , srcMemberType , diag , typeVarMap , flags , recursionCount + 1 ) ) { isAssignable = false ; } } } } } ) ; destType . details . baseClasses . forEach ( ( baseClass ) => { if ( isInstantiableClass ( baseClass ) && ClassType . isProtocolClass ( baseClass ) && ! ClassType . isBuiltIn ( baseClass , 'object' ) && ! ClassType . isBuiltIn ( baseClass , 'Protocol' ) && baseClass . details . typeParameters . length > 0 ) { const specializedDestBaseClass = specializeForBaseClass ( destType , baseClass ) ; const specializedSrcBaseClass = specializeForBaseClass ( srcType , baseClass ) ; if ( ! canAssignProtocolClassToSelf ( specializedDestBaseClass , specializedSrcBaseClass , recursionCount + 1 ) ) { isAssignable = false ; } } } ) ; return isAssignable ; } function canAssignClass ( destType , srcType , diag , typeVarMap , flags , recursionCount , reportErrorsUsingObjType ) { if ( ClassType . isTypedDictClass ( destType ) && ClassType . isTypedDictClass ( srcType ) ) { if ( ! canAssignTypedDict ( evaluatorInterface , destType , srcType , diag , recursionCount ) ) { return false ; } if ( ClassType . isFinal ( destType ) !== ClassType . isFinal ( srcType ) ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typedDictFinalMismatch ( ) . format ( { sourceType : printType ( convertToInstance ( srcType ) ) , destType : printType ( convertToInstance ( destType ) ) , } ) ) ; } return false ; } if ( ( flags & CanAssignFlags . EnforceInvariance ) !== 0 && ! ClassType . isSameGenericClass ( destType , srcType ) ) { return canAssignTypedDict ( evaluatorInterface , srcType , destType , undefined , recursionCount ) ; } return true ; } const promotionList = typePromotions . get ( destType . details . fullName ) ; if ( promotionList && promotionList . some ( ( srcName ) => srcType . details . mro . some ( ( mroClass ) => isClass ( mroClass ) && srcName === mroClass . details . fullName ) ) ) { if ( ( flags & CanAssignFlags . EnforceInvariance ) === 0 ) { return true ; } } const inheritanceChain = [ ] ; const isDerivedFrom = ClassType . isDerivedFrom ( srcType , destType , inheritanceChain ) ; if ( ClassType . isProtocolClass ( destType ) && ! isDerivedFrom ) { if ( ! canAssignClassToProtocol ( destType , srcType , diag ?. createAddendum ( ) , typeVarMap , flags , false , recursionCount + 1 ) ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . protocolIncompatible ( ) . format ( { sourceType : printType ( convertToInstance ( srcType ) ) , destType : printType ( convertToInstance ( destType ) ) , } ) ) ; } return false ; } return true ; } if ( ( flags & CanAssignFlags . EnforceInvariance ) === 0 || ClassType . isSameGenericClass ( srcType , destType ) ) { if ( isDerivedFrom ) { assert ( inheritanceChain . length > 0 ) ; return canAssignClassWithTypeArgs ( destType , srcType , inheritanceChain , diag , typeVarMap , flags , recursionCount + 1 ) ; } } if ( ClassType . isBuiltIn ( destType , 'object' ) ) { if ( ( flags & CanAssignFlags . EnforceInvariance ) === 0 ) { return true ; } } const destErrorType = reportErrorsUsingObjType ? ClassType . cloneAsInstance ( destType ) : destType ; const srcErrorType = reportErrorsUsingObjType ? ClassType . cloneAsInstance ( srcType ) : srcType ; let destErrorTypeText = printType ( destErrorType ) ; let srcErrorTypeText = printType ( srcErrorType ) ; if ( destErrorTypeText === srcErrorTypeText && destType . details . fullName && srcType . details . fullName ) { destErrorTypeText = destType . details . fullName ; srcErrorTypeText = srcType . details . fullName ; } if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeIncompatible ( ) . format ( { sourceType : srcErrorTypeText , destType : destErrorTypeText , } ) ) ; } return false ; } function canAssignClassWithTypeArgs ( destType , srcType , inheritanceChain , diag , typeVarMap , flags , recursionCount ) { let curSrcType = srcType ; let curTypeVarMap = typeVarMap || new TypeVarMap ( getTypeVarScopeId ( destType ) ) ; let effectiveFlags = flags ; if ( ! typeVarMap ) { effectiveFlags &= ~ CanAssignFlags . SkipSolveTypeVars ; } for ( let ancestorIndex = inheritanceChain . length - 1 ; ancestorIndex >= 0 ; ancestorIndex -- ) { const ancestorType = inheritanceChain [ ancestorIndex ] ; if ( isUnknown ( ancestorType ) ) { return true ; } if ( ClassType . isBuiltIn ( ancestorType , 'object' ) ) { return true ; } if ( ancestorIndex < inheritanceChain . length - 1 ) { curSrcType = specializeForBaseClass ( curSrcType , ancestorType ) ; } if ( ancestorIndex === 0 ) { if ( ClassType . isTupleClass ( destType ) ) { if ( destType . tupleTypeArguments && curSrcType . tupleTypeArguments ) { const destTypeArgs = destType . tupleTypeArguments ; let destArgCount = destTypeArgs . length ; const isDestHomogenousType = destArgCount === 2 && isEllipsisType ( destTypeArgs [ 1 ] ) ; if ( isDestHomogenousType ) { destArgCount = 1 ; } const isDestVariadic = destArgCount > 0 && isVariadicTypeVar ( destTypeArgs [ destArgCount - 1 ] ) ; const srcTypeArgs = curSrcType . tupleTypeArguments ; let srcArgCount = srcTypeArgs . length ; const isSrcHomogeneousType = srcArgCount === 2 && isEllipsisType ( srcTypeArgs [ 1 ] ) ; if ( isSrcHomogeneousType ) { srcArgCount = 1 ; } if ( isDestVariadic && isSrcHomogeneousType ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeVarTupleRequiresKnownLength ( ) ) ; } return false ; } if ( ( srcTypeArgs . length === destArgCount && ! isSrcHomogeneousType ) || isDestHomogenousType || isDestVariadic ) { const maxArgCount = Math . max ( destArgCount , srcArgCount ) ; for ( let argIndex = 0 ; argIndex < maxArgCount ; argIndex ++ ) { let srcTypeArgType ; let destTypeArgType ; let isSourceTypeMissing = false ; if ( isSrcHomogeneousType ) { srcTypeArgType = srcTypeArgs [ 0 ] ; } else if ( argIndex < srcTypeArgs . length ) { srcTypeArgType = srcTypeArgs [ argIndex ] ; } else { srcTypeArgType = AnyType . create ( ) ; if ( destType . isTypeArgumentExplicit ) { if ( isDestVariadic && argIndex < destArgCount - 1 && ! isDestHomogenousType ) { isSourceTypeMissing = true ; } } } let movePastSourceArgs = false ; if ( isDestVariadic && argIndex >= destArgCount - 1 ) { destTypeArgType = destTypeArgs [ destArgCount - 1 ] ; if ( tupleClassType && isInstantiableClass ( tupleClassType ) ) { const remainingSrcTypeArgs = srcTypeArgs . slice ( argIndex ) ; srcTypeArgType = convertToInstance ( specializeTupleClass ( tupleClassType , remainingSrcTypeArgs . map ( ( type ) => stripLiteralValue ( type ) ) , true , true , true ) ) ; movePastSourceArgs = true ; } } else if ( isDestHomogenousType ) { destTypeArgType = destTypeArgs [ 0 ] ; } else { destTypeArgType = argIndex < destTypeArgs . length ? destTypeArgs [ argIndex ] : AnyType . create ( ) ; } const entryDiag = diag ?. createAddendum ( ) ; if ( isSourceTypeMissing || ! canAssignType ( destTypeArgType , srcTypeArgType , entryDiag ?. createAddendum ( ) , curTypeVarMap , flags | CanAssignFlags . RetainLiteralsForTypeVar , recursionCount + 1 ) ) { if ( entryDiag ) { entryDiag . addMessage ( Localizer . DiagnosticAddendum . tupleEntryTypeMismatch ( ) . format ( { entry : argIndex + 1 , } ) ) ; } return false ; } if ( movePastSourceArgs ) { argIndex = srcArgCount ; } } } else { if ( isSrcHomogeneousType ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . tupleSizeMismatchIndeterminate ( ) . format ( { expected : destArgCount , } ) ) ; } } else { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . tupleSizeMismatch ( ) . format ( { expected : destArgCount , received : srcTypeArgs . length , } ) ) ; } } return false ; } } return true ; } } const ancestorTypeParams = ClassType . getTypeParameters ( ancestorType ) ; if ( ancestorTypeParams . length === 0 ) { continue ; } if ( ! ancestorType . typeArguments ) { return true ; } if ( ! verifyTypeArgumentsAssignable ( ancestorType , curSrcType , diag , curTypeVarMap , effectiveFlags , recursionCount ) ) { return false ; } curTypeVarMap = new TypeVarMap ( getTypeVarScopeId ( ancestorType ) ) ; effectiveFlags &= ~ CanAssignFlags . SkipSolveTypeVars ; } if ( destType . typeArguments ) { if ( ! verifyTypeArgumentsAssignable ( destType , curSrcType , diag , typeVarMap , flags , recursionCount ) ) { return false ; } } else if ( typeVarMap && destType . details . typeParameters . length > 0 && curSrcType . typeArguments && ! typeVarMap . isLocked ( ) ) { const srcTypeArgs = curSrcType . typeArguments ; for ( let i = 0 ; i < destType . details . typeParameters . length ; i ++ ) { const typeArgType = i < srcTypeArgs . length ? srcTypeArgs [ i ] : UnknownType . create ( ) ; typeVarMap . setTypeVarType ( destType . details . typeParameters [ i ] , undefined , typeArgType ) ; } if ( ClassType . isTupleClass ( curSrcType ) && curSrcType . tupleTypeArguments && destType . details . typeParameters . length >= 1 ) { typeVarMap . setVariadicTypeVar ( destType . details . typeParameters [ 0 ] , curSrcType . tupleTypeArguments ) ; } } return true ; } function getGetterTypeFromProperty ( propertyClass , inferTypeIfNeeded ) { if ( ! ClassType . isPropertyClass ( propertyClass ) ) { return undefined ; } const fgetSymbol = propertyClass . details . fields . get ( 'fget' ) ; if ( fgetSymbol ) { const fgetType = getDeclaredTypeOfSymbol ( fgetSymbol ) ; if ( fgetType && isFunction ( fgetType ) ) { return getFunctionEffectiveReturnType ( fgetType , undefined , inferTypeIfNeeded ) ; } } return undefined ; } function verifyTypeArgumentsAssignable ( destType , srcType , diag , typeVarMap , flags , recursionCount ) { assert ( ClassType . isSameGenericClass ( destType , srcType ) ) ; const destTypeParams = ClassType . getTypeParameters ( destType ) ; let destTypeArgs ; let srcTypeArgs ; if ( ! destType . typeArguments || ! srcType . typeArguments ) { return true ; } if ( ClassType . isTupleClass ( destType ) ) { destTypeArgs = destType . tupleTypeArguments || [ ] ; srcTypeArgs = srcType . tupleTypeArguments ; } else { destTypeArgs = destType . typeArguments ! ; srcTypeArgs = srcType . typeArguments ; } if ( srcTypeArgs ) { for ( let srcArgIndex = 0 ; srcArgIndex < srcTypeArgs . length ; srcArgIndex ++ ) { const srcTypeArg = srcTypeArgs [ srcArgIndex ] ; const destArgIndex = srcArgIndex >= destTypeArgs . length ? destTypeArgs . length - 1 : srcArgIndex ; const destTypeArg = destArgIndex >= 0 ? destTypeArgs [ destArgIndex ] : UnknownType . create ( ) ; const destTypeParam = destArgIndex < destTypeParams . length ? destTypeParams [ destArgIndex ] : undefined ; const assignmentDiag = new DiagnosticAddendum ( ) ; if ( ! destTypeParam || destTypeParam . details . variance === Variance . Covariant ) { if ( ! canAssignType ( destTypeArg , srcTypeArg , assignmentDiag , typeVarMap , flags | CanAssignFlags . RetainLiteralsForTypeVar , recursionCount + 1 ) ) { if ( destTypeParam ) { if ( diag ) { const childDiag = diag . createAddendum ( ) ; childDiag . addMessage ( Localizer . DiagnosticAddendum . typeVarIsCovariant ( ) . format ( { name : TypeVarType . getReadableName ( destTypeParam ) , } ) ) ; childDiag . addAddendum ( assignmentDiag ) ; } } return false ; } } else if ( destTypeParam . details . variance === Variance . Contravariant ) { if ( ! canAssignType ( srcTypeArg , destTypeArg , assignmentDiag , typeVarMap , ( flags ^ CanAssignFlags . ReverseTypeVarMatching ) | CanAssignFlags . RetainLiteralsForTypeVar , recursionCount + 1 ) ) { if ( diag ) { const childDiag = diag . createAddendum ( ) ; childDiag . addMessage ( Localizer . DiagnosticAddendum . typeVarIsContravariant ( ) . format ( { name : TypeVarType . getReadableName ( destTypeParam ) , } ) ) ; childDiag . addAddendum ( assignmentDiag ) ; } return false ; } } else { if ( ! canAssignType ( destTypeArg , srcTypeArg , assignmentDiag , typeVarMap , flags | CanAssignFlags . EnforceInvariance | CanAssignFlags . RetainLiteralsForTypeVar , recursionCount + 1 ) ) { if ( diag ) { const childDiag = diag . createAddendum ( ) ; childDiag . addMessage ( Localizer . DiagnosticAddendum . typeVarIsInvariant ( ) . format ( { name : TypeVarType . getReadableName ( destTypeParam ) , } ) ) ; childDiag . addAddendum ( assignmentDiag ) ; } return false ; } } } } return true ; } function canAssignTypeToTypeVar ( destType , srcType , diag , typeVarMap , flags = CanAssignFlags . Default , recursionCount = 0 ) { let isTypeVarInScope = true ; const isContravariant = ( flags & CanAssignFlags . ReverseTypeVarMatching ) !== 0 ; if ( ! destType . scopeId ) { return true ; } if ( ! typeVarMap . hasSolveForScope ( destType . scopeId ) ) { if ( isAnyOrUnknown ( srcType ) ) { return true ; } if ( ( flags & CanAssignFlags . IgnoreTypeVarScope ) !== 0 ) { return true ; } isTypeVarInScope = false ; if ( ! destType . details . isSynthesized ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeAssignmentMismatch ( ) . format ( { sourceType : printType ( srcType ) , destType : printType ( destType ) , } ) ) ; } return false ; } } if ( destType . details . isParamSpec ) { return canAssignTypeToParamSpec ( destType , srcType , diag , typeVarMap , recursionCount ) ; } if ( destType . details . isVariadic ) { const isVariadicTuple = isClassInstance ( srcType ) && isTupleClass ( srcType ) && ! ! srcType . isTupleForUnpackedVariadicTypeVar ; if ( ! isVariadicTypeVar ( srcType ) && ! isVariadicTuple ) { if ( tupleClassType && isInstantiableClass ( tupleClassType ) ) { srcType = convertToInstance ( specializeTupleClass ( tupleClassType , [ srcType ] , true , true , true ) ) ; } else { srcType = UnknownType . create ( ) ; } } } if ( TypeBase . isInstantiable ( destType ) && isClassInstance ( srcType ) && ClassType . isBuiltIn ( srcType , 'type' ) && ! srcType . typeArguments ) { srcType = AnyType . create ( ) ; } const curEntry = typeVarMap . getTypeVar ( destType ) ; const curNarrowTypeBound = curEntry ?. narrowBound ; const curWideTypeBound = curEntry ?. wideBound ?? destType . details . boundType ; if ( destType . details . constraints . length > 0 ) { let constrainedType ; const concreteSrcType = makeTopLevelTypeVarsConcrete ( srcType ) ; if ( isTypeVar ( srcType ) ) { if ( canAssignType ( destType , concreteSrcType , undefined , new TypeVarMap ( destType . scopeId ) , undefined , recursionCount + 1 ) ) { constrainedType = srcType ; if ( TypeBase . isInstantiable ( srcType ) ) { constrainedType = convertToInstance ( srcType ) ; } } } else { let isCompatible = true ; let unconditionalConstraintIndex ; constrainedType = mapSubtypes ( concreteSrcType , ( srcSubtype ) => { let constrainedSubtype ; if ( isAnyOrUnknown ( srcSubtype ) ) { return srcSubtype ; } let constraintIndexUsed ; destType . details . constraints . forEach ( ( constraint , i ) => { const adjustedConstraint = TypeBase . isInstantiable ( destType ) ? convertToInstantiable ( constraint ) : constraint ; if ( canAssignType ( adjustedConstraint , srcSubtype , undefined , undefined , undefined , recursionCount + 1 ) ) { if ( ! constrainedSubtype || canAssignType ( constrainedSubtype , adjustedConstraint , undefined , undefined , undefined , recursionCount + 1 ) ) { constrainedSubtype = addConditionToType ( constraint , getTypeCondition ( srcSubtype ) ) ; constraintIndexUsed = i ; } } } ) ; if ( ! constrainedSubtype ) { if ( ! isContravariant ) { isCompatible = false ; } } if ( constraintIndexUsed !== undefined && ! getTypeCondition ( srcSubtype ) ) { if ( unconditionalConstraintIndex !== undefined && unconditionalConstraintIndex !== constraintIndexUsed ) { isCompatible = false ; } unconditionalConstraintIndex = constraintIndexUsed ; } return constrainedSubtype ; } ) ; if ( isNever ( constrainedType ) || ! isCompatible ) { constrainedType = undefined ; } if ( ! constrainedType && isUnion ( concreteSrcType ) ) { constrainedType = destType . details . constraints . find ( ( constraint ) => { const adjustedConstraint = TypeBase . isInstantiable ( destType ) ? convertToInstantiable ( constraint ) : constraint ; return canAssignType ( adjustedConstraint , concreteSrcType , undefined , undefined , undefined , recursionCount + 1 ) ; } ) ; } } if ( ! constrainedType ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeConstrainedTypeVar ( ) . format ( { type : printType ( srcType ) , name : destType . details . name , } ) ) ; } return false ; } if ( curNarrowTypeBound && ! isAnyOrUnknown ( curNarrowTypeBound ) ) { if ( ! canAssignType ( curNarrowTypeBound , constrainedType , undefined , undefined , undefined , recursionCount + 1 ) ) { if ( canAssignType ( constrainedType , curNarrowTypeBound , undefined , undefined , undefined , recursionCount + 1 ) ) { if ( ! typeVarMap . isLocked ( ) && isTypeVarInScope ) { typeVarMap . setTypeVarType ( destType , constrainedType ) ; } } else { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeConstrainedTypeVar ( ) . format ( { type : printType ( constrainedType ) , name : printType ( curNarrowTypeBound ) , } ) ) ; } return false ; } } } else { if ( ! typeVarMap . isLocked ( ) && isTypeVarInScope ) { typeVarMap . setTypeVarType ( destType , constrainedType ) ; } } return true ; } let newNarrowTypeBound = curNarrowTypeBound ; let newWideTypeBound = curWideTypeBound ; const diagAddendum = diag ? new DiagnosticAddendum ( ) : undefined ; const retainLiterals = ( flags & CanAssignFlags . RetainLiteralsForTypeVar ) !== 0 || typeVarMap . getRetainLiterals ( destType ) || ( destType . details . boundType && containsLiteralType ( destType . details . boundType ) ) || destType . details . constraints . some ( ( t ) => containsLiteralType ( t ) ) ; let adjSrcType = retainLiterals ? srcType : stripLiteralValue ( srcType ) ; if ( TypeBase . isInstantiable ( destType ) ) { if ( TypeBase . isInstantiable ( adjSrcType ) ) { adjSrcType = convertToInstance ( adjSrcType ) ; } else { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeAssignmentMismatch ( ) . format ( { sourceType : printType ( adjSrcType ) , destType : printType ( destType ) , } ) ) ; } return false ; } } if ( isContravariant || ( flags & CanAssignFlags . AllowTypeVarNarrowing ) !== 0 ) { if ( ! curWideTypeBound ) { newWideTypeBound = adjSrcType ; } else if ( ! isTypeSame ( curWideTypeBound , adjSrcType , undefined , undefined , recursionCount + 1 ) ) { if ( canAssignType ( curWideTypeBound , makeTopLevelTypeVarsConcrete ( adjSrcType ) , diagAddendum , undefined , flags & CanAssignFlags . IgnoreTypeVarScope , recursionCount + 1 ) ) { newWideTypeBound = adjSrcType ; } else if ( ! canAssignType ( adjSrcType , curWideTypeBound , diagAddendum , undefined , flags & CanAssignFlags . IgnoreTypeVarScope , recursionCount + 1 ) ) { if ( diag && diagAddendum ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeAssignmentMismatch ( ) . format ( { sourceType : printType ( adjSrcType ) , destType : printType ( curWideTypeBound ) , } ) ) ; diag . addAddendum ( diagAddendum ) ; } return false ; } } if ( curNarrowTypeBound ) { if ( ! canAssignType ( newWideTypeBound ! , curNarrowTypeBound , undefined , undefined , flags & CanAssignFlags . IgnoreTypeVarScope , recursionCount + 1 ) ) { if ( diag && diagAddendum ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeAssignmentMismatch ( ) . format ( { sourceType : printType ( adjSrcType ) , destType : printType ( curNarrowTypeBound ) , } ) ) ; diag . addAddendum ( diagAddendum ) ; } return false ; } } } else { if ( ! curNarrowTypeBound ) { newNarrowTypeBound = adjSrcType ; } else if ( ! isTypeSame ( curNarrowTypeBound , adjSrcType , undefined , undefined , recursionCount + 1 ) ) { if ( canAssignType ( curNarrowTypeBound , adjSrcType , diagAddendum , typeVarMap , flags , recursionCount + 1 ) ) { if ( isPartlyUnknown ( curNarrowTypeBound ) && canAssignType ( adjSrcType , curNarrowTypeBound , undefined , typeVarMap , flags & CanAssignFlags . IgnoreTypeVarScope , recursionCount + 1 ) ) { newNarrowTypeBound = adjSrcType ; } else { newNarrowTypeBound = curNarrowTypeBound ; } } else { if ( typeVarMap . isLocked ( ) || isTypeVar ( adjSrcType ) ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeAssignmentMismatch ( ) . format ( { sourceType : printType ( curNarrowTypeBound ) , destType : printType ( adjSrcType ) , } ) ) ; } return false ; } if ( isVariadicTypeVar ( destType ) ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeAssignmentMismatch ( ) . format ( { sourceType : printType ( curNarrowTypeBound ) , destType : printType ( adjSrcType ) , } ) ) ; } return false ; } if ( canAssignType ( adjSrcType , curNarrowTypeBound , undefined , typeVarMap , flags & CanAssignFlags . IgnoreTypeVarScope , recursionCount + 1 ) ) { newNarrowTypeBound = adjSrcType ; } else { if ( isUnion ( curNarrowTypeBound ) && curNarrowTypeBound . subtypes . length > maxSubtypesForInferredType && ( destType as TypeVarType ) . details . boundType !== undefined && objectType && isClassInstance ( objectType ) ) { newNarrowTypeBound = combineTypes ( [ curNarrowTypeBound , objectType ] ) ; } else { newNarrowTypeBound = combineTypes ( [ curNarrowTypeBound , adjSrcType ] ) ; } } } } if ( curWideTypeBound && newNarrowTypeBound ) { if ( ! isTypeSame ( curWideTypeBound , newNarrowTypeBound , undefined , undefined , recursionCount + 1 ) ) { let makeConcrete = true ; if ( isTypeVar ( curWideTypeBound ) ) { if ( isTypeSame ( newNarrowTypeBound , curWideTypeBound ) ) { makeConcrete = false ; } else if ( isUnion ( newNarrowTypeBound ) && newNarrowTypeBound . subtypes . some ( ( subtype ) => isTypeSame ( subtype , curWideTypeBound ) ) ) { makeConcrete = false ; } } if ( ! canAssignType ( makeConcrete ? makeTopLevelTypeVarsConcrete ( curWideTypeBound ) : curWideTypeBound , newNarrowTypeBound , undefined , typeVarMap , flags & CanAssignFlags . IgnoreTypeVarScope , recursionCount + 1 ) ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeAssignmentMismatch ( ) . format ( { sourceType : printType ( adjSrcType ) , destType : printType ( curWideTypeBound ) , } ) ) ; } return false ; } } } } if ( destType . details . boundType ) { const updatedType = ( newNarrowTypeBound || newWideTypeBound ) ! ; if ( TypeBase . isInstantiable ( destType ) && ! TypeBase . isInstantiable ( srcType ) ) { return false ; } if ( ! canAssignType ( destType . details . boundType , makeTopLevelTypeVarsConcrete ( updatedType ) , diag ?. createAddendum ( ) , typeVarMap , flags & CanAssignFlags . IgnoreTypeVarScope , recursionCount + 1 ) ) { if ( ! destType . details . isSynthesized ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeBound ( ) . format ( { sourceType : printType ( updatedType ) , destType : printType ( destType . details . boundType ) , name : TypeVarType . getReadableName ( destType ) , } ) ) ; } } return false ; } } if ( ! typeVarMap . isLocked ( ) && isTypeVarInScope ) { typeVarMap . setTypeVarType ( destType , newNarrowTypeBound , newWideTypeBound , retainLiterals ) ; } return true ; } function canAssignTypeToParamSpec ( destType , srcType , diag , typeVarMap , recursionCount = 0 ) { if ( isTypeVar ( srcType ) && srcType . details . isParamSpec ) { const existingEntry = typeVarMap . getParamSpec ( destType ) ; if ( existingEntry ) { if ( existingEntry . parameters . length === 0 && existingEntry . paramSpec ) { if ( isTypeSame ( existingEntry . paramSpec , srcType , undefined , undefined , recursionCount + 1 ) ) { return true ; } } } else { if ( ! typeVarMap . isLocked ( ) && typeVarMap . hasSolveForScope ( destType . scopeId ) ) { typeVarMap . setParamSpec ( destType , { flags : FunctionTypeFlags . None , parameters : [ ] , docString : undefined , paramSpec : srcType , } ) ; } return true ; } } else if ( isFunction ( srcType ) ) { const functionSrcType = srcType ; const parameters = srcType . details . parameters . map ( ( p , index ) => { const paramSpecEntry = { category : p . category , name : p . name , isNameSynthesized : p . isNameSynthesized , hasDefault : ! ! p . hasDefault , type : FunctionType . getEffectiveParameterType ( functionSrcType , index ) , } ; return paramSpecEntry ; } ) ; const existingEntry = typeVarMap . getParamSpec ( destType ) ; if ( existingEntry ) { if ( ! existingEntry . paramSpec && existingEntry . parameters . length === parameters . length && ! existingEntry . parameters . some ( ( existingParam , index ) => { const newParam = parameters [ index ] ; return ( existingParam . category !== newParam . category || existingParam . name !== newParam . name || existingParam . hasDefault !== newParam . hasDefault || ! isTypeSame ( existingParam . type , newParam . type , undefined , undefined , recursionCount + 1 ) ) ; } ) ) { return true ; } } else { if ( ! typeVarMap . isLocked ( ) && typeVarMap . hasSolveForScope ( destType . scopeId ) ) { typeVarMap . setParamSpec ( destType , { parameters , flags : srcType . details . flags , docString : srcType . details . docString , paramSpec : undefined , } ) ; } return true ; } } else if ( isAnyOrUnknown ( srcType ) ) { return true ; } if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeParamSpec ( ) . format ( { type : printType ( srcType ) , name : destType . details . name , } ) ) ; } return false ; } function canAssignType ( destType , srcType , diag ? , typeVarMap ? , flags = CanAssignFlags . Default , recursionCount = 0 ) { destType = transformPossibleRecursiveTypeAlias ( destType ) ; srcType = transformPossibleRecursiveTypeAlias ( srcType ) ; if ( isUnion ( destType ) && destType . subtypes . length === 1 && isVariadicTypeVar ( destType . subtypes [ 0 ] ) ) { destType = destType . subtypes [ 0 ] ; } if ( isUnion ( srcType ) && srcType . subtypes . length === 1 && isVariadicTypeVar ( srcType . subtypes [ 0 ] ) ) { srcType = srcType . subtypes [ 0 ] ; } if ( recursionCount > maxTypeRecursionCount ) { return true ; } if ( destType === srcType ) { if ( isTypeVar ( destType ) && ! destType . details . isParamSpec && ! destType . details . isVariadic && destType . scopeType === TypeVarScopeType . Class && typeVarMap && ! typeVarMap . isLocked ( ) && typeVarMap . hasSolveForScope ( destType . scopeId ) && ! typeVarMap . getTypeVar ( destType ) && ( flags & ( CanAssignFlags . SkipSolveTypeVars | CanAssignFlags . ReverseTypeVarMatching ) ) === 0 ) { typeVarMap . setTypeVarType ( destType , srcType ) ; } return true ; } if ( isUnbound ( destType ) || isUnbound ( srcType ) ) { return true ; } if ( ( flags & CanAssignFlags . OverloadOverlapCheck ) !== 0 ) { srcType = makeTopLevelTypeVarsConcrete ( srcType ) ; } const originalFlags = flags ; flags &= ~ ( CanAssignFlags . AllowBoolTypeGuard | CanAssignFlags . AllowTypeVarNarrowing ) ; if ( isTypeVar ( destType ) ) { if ( canAssignConditionalTypeToTypeVar ( destType , srcType , recursionCount + 1 ) ) { return true ; } if ( isTypeVar ( srcType ) && srcType . details . isSynthesizedSelf && srcType . details . boundType && destType . details . isSynthesizedSelf && destType . details . boundType ) { if ( ( flags & CanAssignFlags . ReverseTypeVarMatching ) === 0 && typeVarMap ) { canAssignTypeToTypeVar ( destType , srcType , diag , typeVarMap , originalFlags , recursionCount + 1 ) ; } return true ; } if ( isVariadicTypeVar ( destType ) && isClassInstance ( srcType ) && isTupleClass ( srcType ) && srcType . tupleTypeArguments && srcType . tupleTypeArguments . length === 1 ) { if ( isTypeSame ( destType , srcType . tupleTypeArguments [ 0 ] , undefined , undefined , recursionCount + 1 ) ) { return true ; } } if ( ( flags & CanAssignFlags . ReverseTypeVarMatching ) === 0 || ! isTypeVar ( srcType ) ) { if ( flags & CanAssignFlags . SkipSolveTypeVars ) { return canAssignType ( makeTopLevelTypeVarsConcrete ( destType ) , makeTopLevelTypeVarsConcrete ( srcType ) , diag , undefined , originalFlags , recursionCount + 1 ) ; } else { if ( ! canAssignTypeToTypeVar ( destType , srcType , diag , typeVarMap ?? new TypeVarMap ( ) , originalFlags , recursionCount + 1 ) ) { return false ; } if ( isAnyOrUnknown ( srcType ) && ( flags & CanAssignFlags . OverloadOverlapCheck ) !== 0 ) { return false ; } return true ; } } } if ( isTypeVar ( srcType ) ) { if ( ( flags & CanAssignFlags . ReverseTypeVarMatching ) !== 0 ) { if ( ! typeVarMap || ! typeVarMap . hasSolveForScope ( getTypeVarScopeId ( srcType ) ) ) { return canAssignType ( makeTopLevelTypeVarsConcrete ( destType ) , makeTopLevelTypeVarsConcrete ( srcType ) , diag , undefined , originalFlags , recursionCount + 1 ) ; } else { if ( canAssignTypeToTypeVar ( srcType as TypeVarType , destType , diag , typeVarMap , originalFlags | CanAssignFlags . AllowTypeVarNarrowing , recursionCount + 1 ) ) { return true ; } let isAssignable = false ; if ( isUnion ( destType ) ) { doForEachSubtype ( destType , ( destSubtype ) => { if ( canAssignTypeToTypeVar ( srcType as TypeVarType , destSubtype , diag , typeVarMap , originalFlags | CanAssignFlags . AllowTypeVarNarrowing , recursionCount + 1 ) ) { isAssignable = true ; } } ) ; } return isAssignable ; } } if ( ( flags & CanAssignFlags . EnforceInvariance ) !== 0 ) { if ( isAnyOrUnknown ( destType ) ) { return true ; } if ( isParamSpec ( srcType ) && isFunction ( destType ) && FunctionType . shouldSkipArgsKwargsCompatibilityCheck ( destType ) && destType . details . parameters . length <= 2 ) { return true ; } if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeAssignmentMismatch ( ) . format ( { sourceType : printType ( srcType ) , destType : printType ( destType ) , } ) ) ; } return false ; } } if ( isAnyOrUnknown ( destType ) ) { return true ; } if ( isAnyOrUnknown ( srcType ) ) { if ( typeVarMap ) { const typeVarSubstitution = isEllipsisType ( srcType ) ? AnyType . create ( ) : srcType ; setTypeArgumentsRecursive ( destType , typeVarSubstitution , typeVarMap ) ; } if ( ( flags & CanAssignFlags . OverloadOverlapCheck ) === 0 ) { return true ; } } if ( isNever ( srcType ) ) { if ( typeVarMap ) { setTypeArgumentsRecursive ( destType , UnknownType . create ( ) , typeVarMap ) ; } return true ; } if ( isUnion ( srcType ) && TypeBase . isSpecialForm ( srcType ) ) { srcType = unionType || objectType || AnyType . create ( ) ; } if ( isUnion ( destType ) ) { if ( isUnion ( srcType ) ) { if ( canAssignFromUnionType ( destType , srcType , undefined , typeVarMap , originalFlags , recursionCount + 1 ) ) { return true ; } } else { const clonedTypeVarMap = typeVarMap ? typeVarMap . clone ( ) : undefined ; if ( canAssignToUnionType ( destType , srcType , undefined , clonedTypeVarMap , originalFlags , recursionCount + 1 ) ) { if ( typeVarMap && clonedTypeVarMap ) { typeVarMap . copyFromClone ( clonedTypeVarMap ) ; } return true ; } } } const expandedSrcType = makeTopLevelTypeVarsConcrete ( srcType ) ; if ( isUnion ( expandedSrcType ) ) { return canAssignFromUnionType ( destType , expandedSrcType , diag , typeVarMap , originalFlags , recursionCount + 1 ) ; } if ( isUnion ( destType ) ) { return canAssignToUnionType ( destType , srcType , diag , typeVarMap , originalFlags , recursionCount + 1 ) ; } if ( isNoneInstance ( destType ) && isNoneInstance ( srcType ) ) { return true ; } if ( isNoneTypeClass ( destType ) && isNoneTypeClass ( srcType ) ) { return true ; } if ( isClassInstance ( srcType ) && ClassType . isBuiltIn ( srcType , 'type' ) ) { const srcTypeArgs = srcType . typeArguments ; if ( srcTypeArgs && srcTypeArgs . length >= 1 ) { if ( isAnyOrUnknown ( srcTypeArgs [ 0 ] ) ) { if ( isClassInstance ( destType ) && ClassType . isBuiltIn ( srcType , 'type' ) ) { return true ; } return TypeBase . isInstantiable ( destType ) ; } if ( isClassInstance ( srcTypeArgs [ 0 ] ) || isTypeVar ( srcTypeArgs [ 0 ] ) ) { if ( canAssignType ( destType , convertToInstantiable ( srcTypeArgs [ 0 ] ) , diag ?. createAddendum ( ) , typeVarMap , flags , recursionCount + 1 ) ) { return true ; } if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeAssignmentMismatch ( ) . format ( { sourceType : printType ( srcType ) , destType : printType ( destType ) , } ) ) ; } return false ; } } } if ( isInstantiableClass ( destType ) ) { const concreteSrcType = makeTopLevelTypeVarsConcrete ( srcType ) ; if ( isInstantiableClass ( concreteSrcType ) ) { if ( ClassType . isProtocolClass ( destType ) ) { if ( ClassType . isProtocolClass ( concreteSrcType ) && isInstantiableClass ( srcType ) && ! srcType . includeSubclasses ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . protocolSourceIsNotConcrete ( ) . format ( { sourceType : printType ( convertToInstance ( srcType ) ) , destType : printType ( destType ) , } ) ) ; } return false ; } } if ( canAssignClass ( destType , concreteSrcType , diag , typeVarMap , flags , recursionCount + 1 , false ) ) { return true ; } if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeAssignmentMismatch ( ) . format ( { sourceType : printType ( srcType ) , destType : printType ( destType ) , } ) ) ; } return false ; } } if ( isClassInstance ( destType ) ) { if ( ClassType . isBuiltIn ( destType , 'Type' ) ) { const destTypeArgs = destType . typeArguments ; if ( destTypeArgs && destTypeArgs . length >= 1 ) { if ( TypeBase . isInstance ( destTypeArgs [ 0 ] ) && TypeBase . isInstantiable ( srcType ) ) { return canAssignType ( destTypeArgs [ 0 ] , convertToInstance ( srcType ) , diag , typeVarMap , flags , recursionCount + 1 ) ; } } } else if ( ClassType . isBuiltIn ( destType , 'type' ) ) { if ( TypeBase . isInstantiable ( srcType ) ) { const isLiteral = isClass ( srcType ) && srcType . literalValue !== undefined ; return ! isLiteral ; } } else if ( ClassType . isBuiltIn ( destType , 'TypeGuard' ) ) { if ( ( originalFlags & CanAssignFlags . AllowBoolTypeGuard ) !== 0 ) { if ( isClassInstance ( srcType ) && ClassType . isBuiltIn ( srcType , 'bool' ) ) { return true ; } } } const concreteSrcType = makeTopLevelTypeVarsConcrete ( srcType ) ; if ( isClass ( concreteSrcType ) && TypeBase . isInstance ( concreteSrcType ) ) { if ( destType . literalValue !== undefined ) { const srcLiteral = concreteSrcType . literalValue ; if ( srcLiteral === undefined || ! ClassType . isLiteralValueSame ( concreteSrcType , destType ) ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . literalAssignmentMismatch ( ) . format ( { sourceType : printType ( srcType ) , destType : printType ( destType ) , } ) ) ; } return false ; } } if ( ! canAssignClass ( ClassType . cloneAsInstantiable ( destType ) , ClassType . cloneAsInstantiable ( concreteSrcType ) , diag , typeVarMap , flags , recursionCount + 1 , true ) ) { return false ; } return true ; } else if ( isFunction ( concreteSrcType ) || isOverloadedFunction ( concreteSrcType ) ) { const destCallbackType = getCallbackProtocolType ( destType ) ; if ( destCallbackType ) { return canAssignType ( destCallbackType , concreteSrcType , diag , typeVarMap , flags , recursionCount + 1 ) ; } if ( objectType && isClassInstance ( objectType ) ) { return canAssignType ( destType , objectType , diag , typeVarMap , flags , recursionCount + 1 ) ; } } else if ( isModule ( concreteSrcType ) ) { if ( ClassType . isBuiltIn ( destType , 'ModuleType' ) ) { return true ; } if ( ClassType . isProtocolClass ( destType ) ) { return canAssignModuleToProtocol ( ClassType . cloneAsInstantiable ( destType ) , concreteSrcType , diag , typeVarMap , flags , recursionCount + 1 ) ; } } else if ( isInstantiableClass ( concreteSrcType ) ) { const callbackType = getCallbackProtocolType ( destType ) ; if ( callbackType ) { return canAssignType ( callbackType , concreteSrcType , diag , typeVarMap , flags , recursionCount + 1 ) ; } if ( ClassType . isProtocolClass ( destType ) ) { return canAssignClassToProtocol ( ClassType . cloneAsInstantiable ( destType ) , concreteSrcType , diag , typeVarMap , flags , true , recursionCount + 1 ) ; } const metaclass = concreteSrcType . details . effectiveMetaclass ; if ( metaclass ) { if ( isAnyOrUnknown ( metaclass ) ) { return true ; } else { return canAssignClass ( ClassType . cloneAsInstantiable ( destType ) , metaclass , diag , typeVarMap , flags , recursionCount + 1 , false ) ; } } } else if ( isAnyOrUnknown ( concreteSrcType ) ) { return ( flags & CanAssignFlags . OverloadOverlapCheck ) === 0 ; } else if ( isUnion ( concreteSrcType ) ) { return canAssignType ( destType , concreteSrcType , diag , typeVarMap , flags , recursionCount + 1 ) ; } } if ( isFunction ( destType ) ) { let srcFunction ; let concreteSrcType = makeTopLevelTypeVarsConcrete ( srcType ) ; if ( isClassInstance ( concreteSrcType ) ) { const callMember = lookUpObjectMember ( concreteSrcType , '__call__' ) ; if ( callMember ) { const memberType = getTypeOfMember ( callMember ) ; if ( isFunction ( memberType ) || isOverloadedFunction ( memberType ) ) { const boundMethod = bindFunctionToClassOrObject ( concreteSrcType , memberType , undefined , undefined , recursionCount + 1 ) ; if ( boundMethod ) { concreteSrcType = removeParamSpecVariadicsFromSignature ( boundMethod ) ; } } } } if ( isInstantiableClass ( concreteSrcType ) && concreteSrcType . literalValue === undefined ) { const constructor = createFunctionFromConstructor ( concreteSrcType ) ; if ( constructor ) { concreteSrcType = constructor ; } } if ( isOverloadedFunction ( concreteSrcType ) ) { if ( destType . details . paramSpec ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . paramSpecOverload ( ) ) ; } return false ; } const overloads = concreteSrcType . overloads ; const overloadIndex = overloads . findIndex ( ( overload ) => { if ( ! FunctionType . isOverloaded ( overload ) ) { return false ; } const typeVarMapClone = typeVarMap ? typeVarMap . clone ( ) : undefined ; return canAssignType ( destType , overload , diag ?. createAddendum ( ) , typeVarMapClone , flags , recursionCount + 1 ) ; } ) ; if ( overloadIndex < 0 ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . noOverloadAssignable ( ) . format ( { type : printType ( destType ) } ) ) ; } return false ; } srcFunction = overloads [ overloadIndex ] ; } else if ( isFunction ( concreteSrcType ) ) { srcFunction = concreteSrcType ; } else if ( isAnyOrUnknown ( concreteSrcType ) ) { return ( flags & CanAssignFlags . OverloadOverlapCheck ) === 0 ; } if ( srcFunction ) { if ( canAssignFunction ( destType , srcFunction , diag ?. createAddendum ( ) , typeVarMap ?? new TypeVarMap ( getTypeVarScopeId ( destType ) ) , flags , recursionCount + 1 ) ) { return true ; } } } if ( isOverloadedFunction ( destType ) ) { const overloadDiag = diag ?. createAddendum ( ) ; const isAssignable = ! destType . overloads . some ( ( destOverload ) => { if ( ! FunctionType . isOverloaded ( destOverload ) ) { return false ; } if ( typeVarMap ) { typeVarMap . addSolveForScope ( getTypeVarScopeId ( destOverload ) ) ; } return ! canAssignType ( destOverload , srcType , overloadDiag ?. createAddendum ( ) , typeVarMap || new TypeVarMap ( getTypeVarScopeId ( destOverload ) ) , flags , recursionCount + 1 ) ; } ) ; if ( ! isAssignable ) { if ( overloadDiag ) { overloadDiag . addMessage ( Localizer . DiagnosticAddendum . overloadNotAssignable ( ) . format ( { name : destType . overloads [ 0 ] . details . name , } ) ) ; } return false ; } return true ; } if ( isClassInstance ( destType ) && ClassType . isBuiltIn ( destType , 'object' ) ) { if ( ( flags & CanAssignFlags . EnforceInvariance ) === 0 ) { return true ; } } if ( isNoneInstance ( srcType ) && isClassInstance ( destType ) && ClassType . isProtocolClass ( destType ) ) { if ( noneType && isInstantiableClass ( noneType ) ) { return canAssignClassToProtocol ( ClassType . cloneAsInstantiable ( destType ) , noneType , diag , typeVarMap , flags , false , recursionCount + 1 ) ; } } if ( isNoneInstance ( destType ) ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . assignToNone ( ) ) ; } return false ; } if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeAssignmentMismatch ( ) . format ( { sourceType : printType ( srcType ) , destType : printType ( destType ) , } ) ) ; } return false ; } function canAssignFromUnionType ( destType , srcType , diag , typeVarMap , flags , recursionCount ) { if ( isTypeSame ( srcType , destType , undefined , undefined , recursionCount + 1 ) ) { return true ; } if ( flags & CanAssignFlags . EnforceInvariance ) { if ( isUnion ( destType ) ) { const remainingDestSubtypes = [ ] ; let remainingSrcSubtypes = [ ... srcType . subtypes ] ; let isIncompatible = false ; destType . subtypes . forEach ( ( destSubtype ) => { if ( requiresSpecialization ( destSubtype ) ) { remainingDestSubtypes . push ( destSubtype ) ; } else { const srcTypeIndex = remainingSrcSubtypes . findIndex ( ( srcSubtype ) => isTypeSame ( srcSubtype , destSubtype , undefined , undefined , recursionCount + 1 ) ) ; if ( srcTypeIndex >= 0 ) { remainingSrcSubtypes . splice ( srcTypeIndex , 1 ) ; } else { isIncompatible = true ; } } } ) ; if ( ! isIncompatible ) { [ ... remainingSrcSubtypes ] . forEach ( ( srcSubtype ) => { const destTypeIndex = remainingDestSubtypes . findIndex ( ( destSubtype ) => isClass ( srcSubtype ) && isClass ( destSubtype ) && TypeBase . isInstance ( srcSubtype ) === TypeBase . isInstance ( destSubtype ) && ClassType . isSameGenericClass ( srcSubtype , destSubtype ) ) ; if ( destTypeIndex >= 0 ) { if ( ! canAssignType ( remainingDestSubtypes [ destTypeIndex ] , srcSubtype , diag ?. createAddendum ( ) , typeVarMap , flags , recursionCount + 1 ) ) { isIncompatible = true ; } remainingDestSubtypes . splice ( destTypeIndex , 1 ) ; remainingSrcSubtypes = remainingSrcSubtypes . filter ( ( t ) => t !== srcSubtype ) ; } } ) ; } if ( ! isIncompatible && ( remainingDestSubtypes . length !== 0 || remainingSrcSubtypes . length !== 0 ) ) { if ( remainingDestSubtypes . length !== 1 || ! isTypeVar ( remainingDestSubtypes [ 0 ] ) || ! canAssignType ( remainingDestSubtypes [ 0 ] , combineTypes ( remainingSrcSubtypes ) , diag ?. createAddendum ( ) , typeVarMap , flags , recursionCount + 1 ) ) { isIncompatible = true ; } } if ( ! isIncompatible ) { return true ; } } } if ( ( flags & CanAssignFlags . AllowTypeVarNarrowing ) !== 0 && isUnion ( destType ) ) { const nonAnySubtypes = destType . subtypes . filter ( ( t ) => ! isAnyOrUnknown ( t ) ) ; if ( nonAnySubtypes . length === 1 && isTypeVar ( nonAnySubtypes [ 0 ] ) ) { canAssignType ( nonAnySubtypes [ 0 ] , srcType , undefined , typeVarMap , flags , recursionCount + 1 ) ; return true ; } } let isIncompatible = false ; doForEachSubtype ( srcType , ( subtype ) => { if ( ! canAssignType ( destType , subtype , undefined , typeVarMap , flags , recursionCount + 1 ) ) { if ( ! canAssignType ( destType , makeTopLevelTypeVarsConcrete ( subtype ) , diag ?. createAddendum ( ) , typeVarMap , flags , recursionCount + 1 ) ) { isIncompatible = true ; } } } ) ; if ( isIncompatible ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeAssignmentMismatch ( ) . format ( { sourceType : printType ( srcType ) , destType : printType ( destType ) , } ) ) ; } return false ; } return true ; } function canAssignToUnionType ( destType , srcType , diag , typeVarMap , flags , recursionCount ) { if ( flags & CanAssignFlags . EnforceInvariance ) { let isIncompatible = false ; doForEachSubtype ( destType , ( subtype , index ) => { if ( ! isIncompatible && ! canAssignType ( subtype , srcType , diag ?. createAddendum ( ) , typeVarMap , flags , recursionCount + 1 ) ) { let skipSubtype = false ; if ( ! isAnyOrUnknown ( subtype ) ) { doForEachSubtype ( destType , ( otherSubtype , otherIndex ) => { if ( index !== otherIndex && ! skipSubtype ) { if ( canAssignType ( otherSubtype , subtype , undefined , undefined , CanAssignFlags . Default , recursionCount + 1 ) ) { skipSubtype = true ; } } } ) ; } if ( ! skipSubtype ) { isIncompatible = true ; } } } ) ; if ( isIncompatible ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeAssignmentMismatch ( ) . format ( { sourceType : printType ( srcType ) , destType : printType ( destType ) , } ) ) ; } return false ; } return true ; } const diagAddendum = diag ? new DiagnosticAddendum ( ) : undefined ; let foundMatch = false ; if ( isNoneInstance ( srcType ) && isOptionalType ( destType ) ) { foundMatch = true ; } else { let bestTypeVarMap ; let bestTypeVarMapScore ; if ( isClassInstance ( srcType ) && isLiteralType ( srcType ) && UnionType . containsType ( destType , srcType , recursionCount + 1 ) ) { return true ; } doForEachSubtype ( destType , ( subtype ) => { const typeVarMapClone = typeVarMap ?. clone ( ) ; if ( canAssignType ( subtype , srcType , diagAddendum ?. createAddendum ( ) , typeVarMapClone , flags , recursionCount + 1 ) ) { foundMatch = true ; if ( typeVarMapClone ) { const typeVarMapScore = typeVarMapClone . getScore ( ) ; if ( bestTypeVarMapScore === undefined || bestTypeVarMapScore <= typeVarMapScore ) { bestTypeVarMapScore = typeVarMapScore ; bestTypeVarMap = typeVarMapClone ; } } } } ) ; if ( typeVarMap && bestTypeVarMap ) { typeVarMap . copyFromClone ( bestTypeVarMap ) ; } } if ( ! foundMatch ) { if ( isTypeVar ( srcType ) && srcType . details . constraints . length > 0 ) { foundMatch = canAssignType ( destType , makeTopLevelTypeVarsConcrete ( srcType ) , diagAddendum ?. createAddendum ( ) , typeVarMap , flags , recursionCount + 1 ) ; } } if ( ! foundMatch ) { if ( diag && diagAddendum ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeAssignmentMismatch ( ) . format ( { sourceType : printType ( srcType ) , destType : printType ( destType ) , } ) ) ; diag . addAddendum ( diagAddendum ) ; } return false ; } return true ; } function canAssignConditionalTypeToTypeVar ( destType , srcType , recursionCount ) { return ! findSubtype ( srcType , ( srcSubtype ) => { if ( isTypeSame ( destType , srcSubtype , true , undefined , recursionCount + 1 ) ) { return false ; } const destTypeVarName = TypeVarType . getNameWithScope ( destType ) ; const applicableConditions = ( getTypeCondition ( srcSubtype ) ?? [ ] ) . filter ( ( constraint ) => constraint . typeVarName === destTypeVarName ) ; if ( applicableConditions . length === 0 ) { return true ; } return ! applicableConditions . some ( ( condition ) => { if ( destType . details . boundType ) { assert ( condition . constraintIndex === 0 ) ; return canAssignType ( destType . details . boundType , srcSubtype , undefined , undefined , undefined , recursionCount + 1 ) ; } if ( destType . details . constraints . length > 0 ) { assert ( condition . constraintIndex < destType . details . constraints . length ) ; const typeVarConstraint = destType . details . constraints [ condition . constraintIndex ] ; assert ( typeVarConstraint !== undefined ) ; return canAssignType ( typeVarConstraint , srcSubtype , undefined , undefined , undefined , recursionCount + 1 ) ; } return true ; } ) ; } ) ; } function createFunctionFromConstructor ( classType ) { const initInfo = lookUpClassMember ( classType , '__init__' , ClassMemberLookupFlags . SkipInstanceVariables | ClassMemberLookupFlags . SkipObjectBaseClass ) ; if ( initInfo ) { const initType = getTypeOfMember ( initInfo ) ; const objectType = ClassType . cloneAsInstance ( classType ) ; const convertInitToConstructor = ( initSubtype ) => { let constructorFunction = bindFunctionToClassOrObject ( objectType , initSubtype ) as FunctionType | undefined ; if ( constructorFunction ) { constructorFunction = FunctionType . clone ( constructorFunction ) ; constructorFunction . details . declaredReturnType = objectType ; if ( constructorFunction . specializedTypes ) { constructorFunction . specializedTypes . returnType = objectType ; } } return constructorFunction ; } ; if ( isFunction ( initType ) ) { return convertInitToConstructor ( initType ) ; } else if ( isOverloadedFunction ( initType ) ) { const initOverloads = [ ] ; initType . overloads . forEach ( ( overload ) => { const converted = convertInitToConstructor ( overload ) ; if ( converted ) { initOverloads . push ( converted ) ; } } ) ; if ( initOverloads . length === 0 ) { return undefined ; } else if ( initOverloads . length === 1 ) { return initOverloads [ 0 ] ; } return OverloadedFunctionType . create ( initOverloads ) ; } } const newInfo = lookUpClassMember ( classType , '__new__' , ClassMemberLookupFlags . SkipInstanceVariables | ClassMemberLookupFlags . SkipObjectBaseClass ) ; if ( newInfo ) { const newType = getTypeOfMember ( newInfo ) ; const convertNewToConstructor = ( newSubtype ) => { return bindFunctionToClassOrObject ( classType , newSubtype , undefined , undefined , undefined , true ) as FunctionType | undefined ; } ; if ( isFunction ( newType ) ) { return convertNewToConstructor ( newType ) ; } else if ( isOverloadedFunction ( newType ) ) { const newOverloads = [ ] ; newType . overloads . forEach ( ( overload ) => { const converted = convertNewToConstructor ( overload ) ; if ( converted ) { newOverloads . push ( converted ) ; } } ) ; if ( newOverloads . length === 0 ) { return undefined ; } else if ( newOverloads . length === 1 ) { return newOverloads [ 0 ] ; } return OverloadedFunctionType . create ( newOverloads ) ; } } const constructorFunction = FunctionType . createInstance ( '__new__' , '' , '' , FunctionTypeFlags . ConstructorMethod | FunctionTypeFlags . SynthesizedMethod ) ; constructorFunction . details . declaredReturnType = ClassType . cloneAsInstance ( classType ) ; FunctionType . addDefaultParameters ( constructorFunction ) ; return constructorFunction ; } function getCallbackProtocolType ( objType ) { if ( ! isClassInstance ( objType ) || ! ClassType . isProtocolClass ( objType ) ) { return undefined ; } for ( const mroClass of objType . details . mro ) { if ( isClass ( mroClass ) && ClassType . isProtocolClass ( mroClass ) ) { for ( const field of mroClass . details . fields ) { if ( field [ 0 ] !== '__call__' && ! field [ 1 ] . isIgnoredForProtocolMatch ( ) ) { let fieldIsPartOfFunction = false ; if ( functionObj && isClass ( functionObj ) ) { if ( functionObj . details . fields . has ( field [ 0 ] ) ) { fieldIsPartOfFunction = true ; } } if ( ! fieldIsPartOfFunction ) { return undefined ; } } } } } const callMember = lookUpObjectMember ( objType , '__call__' ) ; if ( ! callMember ) { return undefined ; } const memberType = getTypeOfMember ( callMember ) ; if ( isFunction ( memberType ) || isOverloadedFunction ( memberType ) ) { const boundMethod = bindFunctionToClassOrObject ( objType , memberType ) ; if ( boundMethod ) { return removeParamSpecVariadicsFromSignature ( boundMethod ) ; } } return undefined ; } function canAssignFunctionParameter ( destType , srcType , paramIndex , diag , destTypeVarMap , srcTypeVarMap , flags , recursionCount ) { if ( isTypeVar ( destType ) && destType . details . isSynthesized && destType . details . boundType && isClassInstance ( destType . details . boundType ) && ClassType . isProtocolClass ( destType . details . boundType ) ) { return true ; } let specializedDestType = applySolvedTypeVars ( destType , destTypeVarMap ) ; if ( requiresSpecialization ( specializedDestType ) ) { if ( ! canAssignType ( srcType , specializedDestType , undefined , destTypeVarMap , ( flags ^ CanAssignFlags . ReverseTypeVarMatching ) | CanAssignFlags . IgnoreTypeVarScope , recursionCount + 1 ) ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . paramAssignment ( ) . format ( { index : paramIndex + 1 , sourceType : printType ( destType ) , destType : printType ( srcType ) , } ) ) ; } return false ; } specializedDestType = applySolvedTypeVars ( destType , destTypeVarMap ) ; } if ( ! canAssignType ( srcType , specializedDestType , diag ?. createAddendum ( ) , srcTypeVarMap , flags , recursionCount + 1 ) ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . paramAssignment ( ) . format ( { index : paramIndex + 1 , sourceType : printType ( destType ) , destType : printType ( srcType ) , } ) ) ; } return false ; } return true ; } function adjustSourceParamDetailsForDestVariadic ( srcType , srcDetails , destDetails ) { if ( destDetails . variadicParamIndex === undefined ) { return ; } if ( srcDetails . params . length < destDetails . variadicParamIndex ) { return ; } if ( srcDetails . argsIndex !== undefined ) { return ; } let srcLastToPackIndex = srcDetails . params . findIndex ( ( p , i ) => i >= destDetails . variadicParamIndex ! && p . source === ParameterSource . KeywordOnly ) ; if ( srcLastToPackIndex < 0 ) { srcLastToPackIndex = srcDetails . params . length ; } let destFirstNonPositional = destDetails . params . length ; if ( destDetails . kwargsIndex !== undefined && destDetails . kwargsIndex > destDetails . variadicParamIndex ) { destFirstNonPositional = destDetails . kwargsIndex ; } const suffixLength = destFirstNonPositional - destDetails . variadicParamIndex - 1 ; const srcPositionalsToPack = srcDetails . params . slice ( destDetails . variadicParamIndex , srcLastToPackIndex - suffixLength ) ; const srcTupleTypes = srcPositionalsToPack . map ( ( entry ) => FunctionType . getEffectiveParameterType ( srcType , entry . index ) ) ; if ( srcTupleTypes . length !== 1 || ! isVariadicTypeVar ( srcTupleTypes [ 0 ] ) ) { let srcPositionalsType ; if ( tupleClassType && isInstantiableClass ( tupleClassType ) ) { srcPositionalsType = convertToInstance ( specializeTupleClass ( tupleClassType , srcTupleTypes , true , true , true ) ) ; } else { srcPositionalsType = UnknownType . create ( ) ; } srcDetails . params = [ ... srcDetails . params . slice ( 0 , destDetails . variadicParamIndex ) , { param : { category : ParameterCategory . Simple , name : '_arg_combined' , isNameSynthesized : true , hasDeclaredType : true , type : srcPositionalsType , } , index : - 1 , source : ParameterSource . PositionOrKeyword , } , ... srcDetails . params . slice ( destDetails . variadicParamIndex + srcPositionalsToPack . length , srcDetails . params . length ) , ] ; if ( srcDetails . kwargsIndex !== undefined ) { srcDetails . kwargsIndex -= srcPositionalsToPack . length - 1 ; } if ( srcDetails . firstKeywordOnlyIndex !== undefined ) { srcDetails . firstKeywordOnlyIndex -= srcPositionalsToPack . length - 1 ; } } } function canAssignFunction ( destType , srcType , diag , typeVarMap , flags , recursionCount ) { let canAssign = true ; const checkReturnType = ( flags & CanAssignFlags . SkipFunctionReturnTypeCheck ) === 0 ; flags &= ~ CanAssignFlags . SkipFunctionReturnTypeCheck ; destType = removeParamSpecVariadicsFromFunction ( destType ) ; srcType = removeParamSpecVariadicsFromFunction ( srcType ) ; const destParamDetails = getParameterListDetails ( destType ) ; const srcParamDetails = getParameterListDetails ( srcType ) ; adjustSourceParamDetailsForDestVariadic ( srcType , srcParamDetails , destParamDetails ) ; const srcTypeVarMap = new TypeVarMap ( getTypeVarScopeId ( srcType ) ) ; const isParamSpecInvolved = ( flags & CanAssignFlags . ReverseTypeVarMatching ) !== 0 ? ! ! srcType . details . paramSpec : ! ! destType . details . paramSpec ; const destPositionalCount = destParamDetails . argsIndex ?? destParamDetails . firstKeywordOnlyIndex ?? destParamDetails . params . length ; const srcPositionalCount = srcParamDetails . argsIndex ?? srcParamDetails . firstKeywordOnlyIndex ?? srcParamDetails . params . length ; const positionalsToMatch = Math . min ( destPositionalCount , srcPositionalCount ) ; for ( let paramIndex = 0 ; paramIndex < positionalsToMatch ; paramIndex ++ ) { const destParam = destParamDetails . params [ paramIndex ] ; const srcParam = srcParamDetails . params [ paramIndex ] ; const srcParamType = srcParam . index >= 0 ? FunctionType . getEffectiveParameterType ( srcType , srcParam . index ) : srcParam . param . type ; const destParamType = FunctionType . getEffectiveParameterType ( destType , destParam . index ) ; const destParamName = destParam . param . name ?? '' ; const srcParamName = srcParam . param . name ?? '' ; if ( destParamName && ! isPrivateOrProtectedName ( destParamName ) && ! isPrivateOrProtectedName ( srcParamName ) ) { const isDestPositionalOnly = destParam . source === ParameterSource . PositionOnly ; if ( ! isDestPositionalOnly && destParamName !== srcParamName ) { if ( diag ) { diag . createAddendum ( ) . addMessage ( Localizer . DiagnosticAddendum . functionParamName ( ) . format ( { srcName : srcParamName , destName : destParamName , } ) ) ; } canAssign = false ; } } if ( ! ! destParam . param . hasDefault && ! srcParam . param . hasDefault ) { if ( diag ) { diag . createAddendum ( ) . addMessage ( Localizer . DiagnosticAddendum . functionParamDefaultMissing ( ) . format ( { name : srcParamName , } ) ) ; } canAssign = false ; } if ( paramIndex === 0 && srcType . details . name === '__init__' && FunctionType . isInstanceMethod ( srcType ) && destType . details . name === '__init__' && FunctionType . isInstanceMethod ( destType ) && FunctionType . isOverloaded ( destType ) && destParam . param . hasDeclaredType ) { continue ; } if ( ! canAssignFunctionParameter ( destParamType , srcParamType , paramIndex , diag ?. createAddendum ( ) , typeVarMap , srcTypeVarMap , flags , recursionCount ) ) { if ( ( flags & CanAssignFlags . SkipSelfClsTypeCheck ) === 0 || ! isTypeVar ( srcParamType ) || ! srcParamType . details . isSynthesized ) { canAssign = false ; } } } if ( ! FunctionType . shouldSkipArgsKwargsCompatibilityCheck ( destType ) && destParamDetails . firstPositionOrKeywordIndex < srcParamDetails . positionOnlyParamCount && ! isParamSpecInvolved ) { if ( diag ) { diag . createAddendum ( ) . addMessage ( Localizer . DiagnosticAddendum . argsPositionOnly ( ) . format ( { expected : srcParamDetails . positionOnlyParamCount , received : destParamDetails . firstPositionOrKeywordIndex , } ) ) ; } canAssign = false ; } if ( destParamDetails . variadicArgsIndex !== undefined ) { const remainingSrcPositionals = [ ] ; if ( destPositionalCount < srcPositionalCount ) { remainingSrcPositionals . push ( ... srcParamDetails . params . slice ( destPositionalCount , srcPositionalCount ) . map ( ( param ) => param . param . type ) ) ; } let isSourceNonVariadicArgs = false ; if ( srcParamDetails . argsIndex !== undefined ) { const srcArgsType = FunctionType . getEffectiveParameterType ( srcType , srcParamDetails . params [ srcParamDetails . argsIndex ] . index ) ; if ( isVariadicTypeVar ( srcArgsType ) ) { remainingSrcPositionals . push ( srcArgsType ) ; } else { isSourceNonVariadicArgs = true ; } } let srcPositionalsType ; if ( remainingSrcPositionals . length === 1 && isVariadicTypeVar ( remainingSrcPositionals [ 0 ] ) ) { srcPositionalsType = remainingSrcPositionals [ 0 ] ; } else { if ( tupleClassType && isInstantiableClass ( tupleClassType ) ) { srcPositionalsType = convertToInstance ( specializeTupleClass ( tupleClassType , remainingSrcPositionals , true , true , true ) ) ; } else { srcPositionalsType = UnknownType . create ( ) ; } } if ( isSourceNonVariadicArgs ) { if ( diag ) { diag . createAddendum ( ) . addMessage ( Localizer . DiagnosticAddendum . argsParamWithVariadic ( ) . format ( { paramName : srcParamDetails . params [ srcParamDetails . argsIndex ! ] . param . name ! , } ) ) ; } canAssign = false ; } else if ( destParamDetails . argsIndex !== undefined ) { const destArgsIndex = destParamDetails . params [ destParamDetails . argsIndex ] . index ; if ( ! canAssignFunctionParameter ( FunctionType . getEffectiveParameterType ( destType , destArgsIndex ) , srcPositionalsType , destArgsIndex , diag ?. createAddendum ( ) , typeVarMap , srcTypeVarMap , flags , recursionCount ) ) { canAssign = false ; } } } else if ( destPositionalCount < srcPositionalCount ) { if ( ! isParamSpecInvolved ) { const nonDefaultSrcParamCount = srcParamDetails . params . filter ( ( p ) => ! ! p . param . name && ! p . param . hasDefault && p . param . category === ParameterCategory . Simple ) . length ; if ( destParamDetails . argsIndex === undefined ) { if ( destPositionalCount < nonDefaultSrcParamCount ) { if ( destParamDetails . firstPositionOrKeywordIndex > 0 && destParamDetails . firstPositionOrKeywordIndex < srcPositionalCount ) { if ( diag ) { diag . createAddendum ( ) . addMessage ( Localizer . DiagnosticAddendum . functionTooFewParams ( ) . format ( { expected : nonDefaultSrcParamCount , received : destPositionalCount , } ) ) ; } canAssign = false ; } } } else { const destArgsType = FunctionType . getEffectiveParameterType ( destType , destParamDetails . params [ destParamDetails . argsIndex ] . index ) ; if ( ! isAnyOrUnknown ( destArgsType ) ) { for ( let paramIndex = destPositionalCount ; paramIndex < srcPositionalCount ; paramIndex ++ ) { const srcParamType = FunctionType . getEffectiveParameterType ( srcType , srcParamDetails . params [ paramIndex ] . index ) ; if ( ! canAssignFunctionParameter ( destArgsType , srcParamType , paramIndex , diag ?. createAddendum ( ) , typeVarMap , srcTypeVarMap , flags , recursionCount ) ) { canAssign = false ; } } } } } } else if ( srcPositionalCount < destPositionalCount ) { if ( srcParamDetails . argsIndex !== undefined ) { const srcArgsType = FunctionType . getEffectiveParameterType ( srcType , srcParamDetails . params [ srcParamDetails . argsIndex ] . index ) ; for ( let paramIndex = srcPositionalCount ; paramIndex < destPositionalCount ; paramIndex ++ ) { const destParamType = FunctionType . getEffectiveParameterType ( destType , destParamDetails . params [ paramIndex ] . index ) ; if ( isVariadicTypeVar ( destParamType ) && ! isVariadicTypeVar ( srcArgsType ) ) { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeVarTupleRequiresKnownLength ( ) ) ; } canAssign = false ; } else if ( ! canAssignFunctionParameter ( destParamType , srcArgsType , paramIndex , diag ?. createAddendum ( ) , typeVarMap , srcTypeVarMap , flags , recursionCount ) ) { canAssign = false ; } } } else { if ( diag ) { diag . addMessage ( Localizer . DiagnosticAddendum . functionTooManyParams ( ) . format ( { expected : srcPositionalCount , received : destPositionalCount , } ) ) ; } canAssign = false ; } } if ( srcParamDetails . argsIndex !== undefined && destParamDetails . argsIndex !== undefined ) { const srcArgsIndex = srcParamDetails . params [ srcParamDetails . argsIndex ] . index ; const srcArgsType = FunctionType . getEffectiveParameterType ( srcType , srcArgsIndex ) ; const destArgsIndex = destParamDetails . params [ destParamDetails . argsIndex ] . index ; const destArgsType = FunctionType . getEffectiveParameterType ( destType , destArgsIndex ) ; if ( ! canAssignFunctionParameter ( destArgsType , srcArgsType , destArgsIndex , diag ?. createAddendum ( ) , typeVarMap , srcTypeVarMap , flags , recursionCount ) ) { canAssign = false ; } } if ( ! FunctionType . shouldSkipArgsKwargsCompatibilityCheck ( destType ) && srcParamDetails . argsIndex === undefined && destParamDetails . argsIndex !== undefined && destParamDetails . variadicArgsIndex === undefined && ! isParamSpecInvolved ) { if ( diag ) { diag . createAddendum ( ) . addMessage ( Localizer . DiagnosticAddendum . argsParamMissing ( ) . format ( { paramName : destParamDetails . params [ destParamDetails . argsIndex ] . param . name ?? '' , } ) ) ; } canAssign = false ; } if ( ! isParamSpecInvolved ) { const destParamMap = new Map < string , FunctionParameter > ( ) ; if ( destParamDetails . firstKeywordOnlyIndex !== undefined ) { destParamDetails . params . forEach ( ( param , index ) => { if ( index >= destParamDetails . firstKeywordOnlyIndex ! ) { if ( param . param . name && param . param . category === ParameterCategory . Simple ) { destParamMap . set ( param . param . name , param . param ) ; } } } ) ; } let srcStartOfNamed = srcParamDetails . firstKeywordOnlyIndex !== undefined ? srcParamDetails . firstKeywordOnlyIndex : srcParamDetails . params . length ; if ( destPositionalCount < srcPositionalCount && destParamDetails . argsIndex === undefined ) { srcStartOfNamed = destPositionalCount ; } if ( srcStartOfNamed >= 0 ) { srcParamDetails . params . forEach ( ( srcParam , index ) => { if ( index >= srcStartOfNamed ) { if ( srcParam . param . name && srcParam . param . category === ParameterCategory . Simple ) { const destParam = destParamMap . get ( srcParam . param . name ) ; const paramDiag = diag ?. createAddendum ( ) ; if ( ! destParam ) { if ( destParamDetails . kwargsIndex === undefined && ! srcParam . param . hasDefault ) { if ( paramDiag ) { paramDiag . addMessage ( Localizer . DiagnosticAddendum . namedParamMissingInDest ( ) . format ( { name : srcParam . param . name , } ) ) ; } canAssign = false ; } else if ( destParamDetails . kwargsIndex !== undefined ) { const destKwargsIndex = destParamDetails . params [ destParamDetails . kwargsIndex ] . index ; const destKwargsType = FunctionType . getEffectiveParameterType ( destType , destKwargsIndex ) ; if ( ! canAssignFunctionParameter ( destKwargsType , srcParam . param . type , destKwargsIndex , diag ?. createAddendum ( ) , typeVarMap , srcTypeVarMap , flags , recursionCount ) ) { canAssign = false ; } } } else { const specializedDestParamType = typeVarMap ? applySolvedTypeVars ( destParam . type , typeVarMap ) : destParam . type ; if ( ! canAssignType ( srcParam . param . type , specializedDestParamType , paramDiag ?. createAddendum ( ) , undefined , flags , recursionCount + 1 ) ) { if ( paramDiag ) { paramDiag . addMessage ( Localizer . DiagnosticAddendum . namedParamTypeMismatch ( ) . format ( { name : srcParam . param . name , sourceType : printType ( specializedDestParamType ) , destType : printType ( srcParam . param . type ) , } ) ) ; } canAssign = false ; } if ( ! ! destParam . hasDefault && ! srcParam . param . hasDefault ) { if ( diag ) { diag . createAddendum ( ) . addMessage ( Localizer . DiagnosticAddendum . functionParamDefaultMissing ( ) . format ( { name : srcParam . param . name , } ) ) ; } canAssign = false ; } destParamMap . delete ( srcParam . param . name ) ; } } } } ) ; } destParamMap . forEach ( ( destParam , paramName ) => { if ( srcParamDetails . kwargsIndex !== undefined && destParam . name ) { const srcKwargsIndex = srcParamDetails . params [ srcParamDetails . kwargsIndex ] . index ; const srcKwargsType = FunctionType . getEffectiveParameterType ( srcType , srcKwargsIndex ) ; if ( ! canAssignFunctionParameter ( destParam . type , srcKwargsType , destType . details . parameters . findIndex ( ( p ) => p === destParam ) , diag ?. createAddendum ( ) , typeVarMap , srcTypeVarMap , flags , recursionCount ) ) { canAssign = false ; } destParamMap . delete ( destParam . name ) ; } else { if ( diag ) { diag . createAddendum ( ) . addMessage ( Localizer . DiagnosticAddendum . namedParamMissingInSource ( ) . format ( { name : paramName } ) ) ; } canAssign = false ; } } ) ; if ( srcParamDetails . kwargsIndex !== undefined && destParamDetails . kwargsIndex !== undefined ) { const srcKwargsIndex = srcParamDetails . params [ srcParamDetails . kwargsIndex ] . index ; const srcKwargsType = FunctionType . getEffectiveParameterType ( srcType , srcKwargsIndex ) ; const destKwargsIndex = destParamDetails . params [ destParamDetails . kwargsIndex ] . index ; const destKwargsType = FunctionType . getEffectiveParameterType ( destType , destKwargsIndex ) ; if ( ! canAssignFunctionParameter ( destKwargsType , srcKwargsType , destKwargsIndex , diag ?. createAddendum ( ) , typeVarMap , srcTypeVarMap , flags , recursionCount ) ) { canAssign = false ; } } if ( ! FunctionType . shouldSkipArgsKwargsCompatibilityCheck ( destType ) && srcParamDetails . kwargsIndex === undefined && destParamDetails . kwargsIndex !== undefined ) { if ( diag ) { diag . createAddendum ( ) . addMessage ( Localizer . DiagnosticAddendum . kwargsParamMissing ( ) . format ( { paramName : destParamDetails . params [ destParamDetails . kwargsIndex ] . param . name ! , } ) ) ; } canAssign = false ; } } if ( isParamSpecInvolved && srcType . details . paramSpec ?. nameWithScope === destType . details . paramSpec ?. nameWithScope ) { if ( srcType . details . parameters . length !== destType . details . parameters . length ) { canAssign = false ; } } if ( typeVarMap && ! typeVarMap . isLocked ( ) ) { srcTypeVarMap . getTypeVars ( ) . forEach ( ( typeVarEntry ) => { canAssignType ( typeVarEntry . typeVar , srcTypeVarMap . getTypeVarType ( typeVarEntry . typeVar ) ! , undefined , typeVarMap ) ; } ) ; typeVarMap . getTypeVars ( ) . forEach ( ( entry ) => { if ( entry . narrowBound ) { const specializedType = applySolvedTypeVars ( entry . narrowBound , typeVarMap ) ; if ( specializedType !== entry . narrowBound ) { typeVarMap . setTypeVarType ( entry . typeVar , specializedType , entry . wideBound , entry . retainLiteral ) ; } } } ) ; if ( isParamSpecInvolved ) { const effectiveDestType = ( flags & CanAssignFlags . ReverseTypeVarMatching ) === 0 ? destType : srcType ; const effectiveSrcType = ( flags & CanAssignFlags . ReverseTypeVarMatching ) === 0 ? srcType : destType ; if ( effectiveDestType . details . paramSpec ) { typeVarMap . setParamSpec ( effectiveDestType . details . paramSpec , { parameters : effectiveSrcType . details . parameters . map ( ( p , index ) => { const paramSpecEntry = { category : p . category , name : p . name , isNameSynthesized : p . isNameSynthesized , hasDefault : ! ! p . hasDefault , type : FunctionType . getEffectiveParameterType ( effectiveSrcType , index ) , } ; return paramSpecEntry ; } ) . slice ( effectiveDestType . details . parameters . filter ( ( p ) => p . name ) . length , effectiveSrcType . details . parameters . length ) , docString : effectiveSrcType . details . docString , flags : effectiveSrcType . details . flags , paramSpec : effectiveSrcType . details . paramSpec ? ( convertToInstance ( effectiveSrcType . details . paramSpec ) as TypeVarType ) : undefined , } ) ; } } } if ( checkReturnType ) { const destReturnType = getFunctionEffectiveReturnType ( destType ) ; if ( ! isAnyOrUnknown ( destReturnType ) ) { const srcReturnType = applySolvedTypeVars ( getFunctionEffectiveReturnType ( srcType ) , srcTypeVarMap ) ; const returnDiag = diag ?. createAddendum ( ) ; let isReturnTypeCompatible = false ; if ( isNoReturnType ( srcReturnType ) ) { isReturnTypeCompatible = true ; } else if ( canAssignType ( destReturnType , srcReturnType , returnDiag ?. createAddendum ( ) , typeVarMap , flags , recursionCount + 1 ) ) { isReturnTypeCompatible = true ; } else { if ( isClassInstance ( srcReturnType ) && ClassType . isBuiltIn ( srcReturnType , 'TypeGuard' ) && boolClassType && isInstantiableClass ( boolClassType ) ) { if ( canAssignType ( destReturnType , ClassType . cloneAsInstance ( boolClassType ) , returnDiag ?. createAddendum ( ) , typeVarMap , flags , recursionCount + 1 ) ) { isReturnTypeCompatible = true ; } } } if ( ! isReturnTypeCompatible ) { if ( returnDiag ) { returnDiag . addMessage ( Localizer . DiagnosticAddendum . functionReturnTypeMismatch ( ) . format ( { sourceType : printType ( srcReturnType ) , destType : printType ( destReturnType ) , } ) ) ; } canAssign = false ; } } } return canAssign ; } function replaceTypeArgsWithAny ( declaredType , assignedType ) { if ( assignedType . details . typeParameters . length > 0 && assignedType . typeArguments && assignedType . typeArguments . length <= assignedType . details . typeParameters . length ) { const typeVarMap = new TypeVarMap ( getTypeVarScopeId ( assignedType ) ) ; populateTypeVarMapBasedOnExpectedType ( ClassType . cloneForSpecialization ( assignedType , undefined , false ) , ClassType . cloneAsInstance ( declaredType ) , typeVarMap , [ ] ) ; let replacedTypeArg = false ; const newTypeArgs = assignedType . typeArguments . map ( ( typeArg , index ) => { const typeParam = assignedType . details . typeParameters [ index ] ; const expectedTypeArgType = typeVarMap . getTypeVarType ( typeParam ) ; if ( expectedTypeArgType ) { if ( isAny ( expectedTypeArgType ) || isAnyOrUnknown ( typeArg ) ) { replacedTypeArg = true ; return expectedTypeArgType ; } } return typeArg ; } ) ; if ( replacedTypeArg ) { return ClassType . cloneForSpecialization ( assignedType , newTypeArgs , true ) ; } } return undefined ; } function narrowTypeBasedOnAssignment ( declaredType , assignedType ) { const diag = new DiagnosticAddendum ( ) ; const narrowedType = mapSubtypes ( assignedType , ( assignedSubtype ) => { const narrowedSubtype = mapSubtypes ( declaredType , ( declaredSubtype ) => { if ( isAnyOrUnknown ( declaredType ) ) { return declaredType ; } if ( canAssignType ( declaredSubtype , assignedSubtype , diag ) ) { if ( isInstantiableClass ( declaredSubtype ) && isInstantiableClass ( assignedSubtype ) ) { const result = replaceTypeArgsWithAny ( declaredSubtype , assignedSubtype ) ; if ( result ) { assignedSubtype = result ; } } else if ( isClassInstance ( declaredSubtype ) && isClassInstance ( assignedSubtype ) ) { const result = replaceTypeArgsWithAny ( ClassType . cloneAsInstantiable ( declaredSubtype ) , ClassType . cloneAsInstantiable ( assignedSubtype ) ) ; if ( result ) { assignedSubtype = ClassType . cloneAsInstance ( result ) ; } } else if ( ! isTypeVar ( declaredSubtype ) && isTypeVar ( assignedSubtype ) ) { return declaredType ; } else if ( isAnyOrUnknown ( assignedSubtype ) ) { return declaredType ; } return assignedSubtype ; } return undefined ; } ) ; if ( isNever ( narrowedSubtype ) ) { return assignedSubtype ; } return narrowedSubtype ; } ) ; if ( isAnyOrUnknown ( assignedType ) ) { return declaredType ; } return narrowedType ; } function canOverrideMethod ( baseMethod , overrideMethod , diag , enforceParamNames = true ) { if ( isOverloadedFunction ( baseMethod ) ) { baseMethod = baseMethod . overloads [ baseMethod . overloads . length - 1 ] ; } if ( ! isFunction ( baseMethod ) ) { diag . addMessage ( Localizer . DiagnosticAddendum . overrideType ( ) . format ( { type : printType ( baseMethod ) } ) ) ; return false ; } let canOverride = true ; const baseParams = baseMethod . details . parameters ; const overrideParams = overrideMethod . details . parameters ; const overrideArgsParam = overrideParams . find ( ( param ) => param . category === ParameterCategory . VarArgList && ! ! param . name ) ; const overrideKwargsParam = overrideParams . find ( ( param ) => param . category === ParameterCategory . VarArgDictionary && ! ! param . name ) ; let foundParamCountMismatch = false ; if ( overrideParams . length < baseParams . length ) { if ( ! overrideArgsParam || ! overrideKwargsParam ) { foundParamCountMismatch = true ; } } else if ( overrideParams . length > baseParams . length ) { for ( let i = baseParams . length ; i < overrideParams . length ; i ++ ) { const overrideParam = overrideParams [ i ] ; if ( overrideParam . category === ParameterCategory . Simple && overrideParam . name && ! overrideParam . hasDefault ) { foundParamCountMismatch = true ; } } } if ( foundParamCountMismatch ) { diag . addMessage ( Localizer . DiagnosticAddendum . overrideParamCount ( ) . format ( { baseCount : baseParams . length , overrideCount : overrideParams . length , } ) ) ; canOverride = false ; } const paramCount = Math . min ( baseParams . length , overrideParams . length ) ; const positionOnlyIndex = baseParams . findIndex ( ( param ) => ! param . name && param . category === ParameterCategory . Simple ) ; for ( let i = 0 ; i < paramCount ; i ++ ) { if ( i === 0 ) { if ( FunctionType . isInstanceMethod ( overrideMethod ) || FunctionType . isClassMethod ( overrideMethod ) || FunctionType . isConstructorMethod ( overrideMethod ) ) { continue ; } } const baseParam = baseParams [ i ] ; const overrideParam = overrideParams [ i ] ; if ( i > positionOnlyIndex && ! isPrivateOrProtectedName ( baseParam . name || '' ) && baseParam . category === ParameterCategory . Simple && baseParam . name !== overrideParam . name ) { if ( overrideParam . category === ParameterCategory . Simple ) { if ( enforceParamNames ) { diag . addMessage ( Localizer . DiagnosticAddendum . overrideParamName ( ) . format ( { index : i + 1 , baseName : baseParam . name || '*' , overrideName : overrideParam . name || '*' , } ) ) ; canOverride = false ; } } } else { const baseParamType = FunctionType . getEffectiveParameterType ( baseMethod , i ) ; const overrideParamType = FunctionType . getEffectiveParameterType ( overrideMethod , i ) ; const baseIsSynthesizedTypeVar = isTypeVar ( baseParamType ) && baseParamType . details . isSynthesized ; const overrideIsSynthesizedTypeVar = isTypeVar ( overrideParamType ) && overrideParamType . details . isSynthesized ; if ( ! baseIsSynthesizedTypeVar && ! overrideIsSynthesizedTypeVar ) { if ( baseParam . category !== overrideParam . category || ! canAssignType ( overrideParamType , baseParamType , diag . createAddendum ( ) , undefined , CanAssignFlags . SkipSolveTypeVars ) ) { diag . addMessage ( Localizer . DiagnosticAddendum . overrideParamType ( ) . format ( { index : i + 1 , baseType : printType ( baseParamType ) , overrideType : printType ( overrideParamType ) , } ) ) ; canOverride = false ; } } } } const baseReturnType = getFunctionEffectiveReturnType ( baseMethod ) ; const overrideReturnType = getFunctionEffectiveReturnType ( overrideMethod ) ; if ( ! canAssignType ( baseReturnType , overrideReturnType , diag . createAddendum ( ) , undefined , CanAssignFlags . SkipSolveTypeVars ) ) { diag . addMessage ( Localizer . DiagnosticAddendum . overrideReturnType ( ) . format ( { baseType : printType ( baseReturnType ) , overrideType : printType ( overrideReturnType ) , } ) ) ; canOverride = false ; } return canOverride ; } function canAssignToTypeVar ( destType , srcType , diag , flags = CanAssignFlags . Default , recursionCount = 0 ) { if ( recursionCount > maxTypeRecursionCount ) { return true ; } if ( isAnyOrUnknown ( srcType ) ) { return true ; } let effectiveSrcType = srcType ; if ( isTypeVar ( srcType ) ) { if ( isTypeSame ( srcType , destType , undefined , undefined , recursionCount + 1 ) ) { return true ; } effectiveSrcType = makeTopLevelTypeVarsConcrete ( srcType ) ; } if ( destType . details . boundType ) { if ( ! canAssignType ( destType . details . boundType , effectiveSrcType , diag . createAddendum ( ) , undefined , flags , recursionCount + 1 ) ) { if ( ! destType . details . isSynthesized ) { diag . addMessage ( Localizer . DiagnosticAddendum . typeBound ( ) . format ( { sourceType : printType ( effectiveSrcType ) , destType : printType ( destType . details . boundType ) , name : TypeVarType . getReadableName ( destType ) , } ) ) ; } return false ; } } if ( destType . details . isParamSpec ) { if ( isParamSpec ( srcType ) ) { return true ; } if ( isFunction ( srcType ) && FunctionType . isParamSpecValue ( srcType ) ) { return true ; } if ( isClassInstance ( srcType ) && ClassType . isBuiltIn ( srcType , 'Concatenate' ) ) { return true ; } diag . addMessage ( Localizer . DiagnosticAddendum . typeParamSpec ( ) . format ( { type : printType ( srcType ) , name : TypeVarType . getReadableName ( destType ) , } ) ) ; return false ; } if ( isTypeVar ( srcType ) && srcType . details . isParamSpec ) { diag . addMessage ( Localizer . Diagnostic . paramSpecContext ( ) ) ; return false ; } const constraints = destType . details . constraints ; if ( constraints . length === 0 ) { return true ; } if ( isTypeVar ( srcType ) && srcType . details . constraints . length > 0 ) { if ( srcType . details . constraints . every ( ( sourceConstraint ) => { return constraints . some ( ( destConstraint ) => canAssignType ( destConstraint , sourceConstraint ) ) ; } ) ) { return true ; } } else { for ( const constraint of constraints ) { if ( canAssignType ( constraint , effectiveSrcType ) ) { return true ; } } } diag . addMessage ( Localizer . DiagnosticAddendum . typeConstrainedTypeVar ( ) . format ( { type : printType ( srcType ) , name : TypeVarType . getReadableName ( destType ) , } ) ) ; return false ; } function getAbstractMethods ( classType ) { const symbolTable = new Map < string , AbstractMethod > ( ) ; classType . details . mro . forEach ( ( mroClass ) => { if ( isInstantiableClass ( mroClass ) ) { mroClass . details . fields . forEach ( ( symbol , symbolName ) => { if ( symbol . isClassMember ( ) ) { let isAbstract ; const decl = getLastTypedDeclaredForSymbol ( symbol ) ; if ( decl && decl . type === DeclarationType . Function ) { const functionFlags = getFunctionFlagsFromDecorators ( decl . node , true ) ; isAbstract = ! ! ( functionFlags & FunctionTypeFlags . AbstractMethod ) ; } else { isAbstract = false ; } if ( ! symbolTable . has ( symbolName ) ) { symbolTable . set ( symbolName , { symbol , symbolName , isAbstract , classType : mroClass , } ) ; } } } ) ; } } ) ; const methodList = [ ] ; symbolTable . forEach ( ( method ) => { if ( method . isAbstract ) { methodList . push ( method ) ; } } ) ; return methodList ; } function bindFunctionToClassOrObject ( baseType , memberType , memberClass ? , errorNode ? , recursionCount = 0 , treatConstructorAsClassMember = false , firstParamType ? ) { if ( isFunction ( memberType ) ) { if ( ! baseType ) { return FunctionType . clone ( memberType , true ) ; } if ( FunctionType . isInstanceMethod ( memberType ) ) { const baseObj = isClassInstance ( baseType ) ? baseType : ClassType . cloneAsInstance ( specializeClassType ( baseType ) ) ; return partiallySpecializeFunctionForBoundClassOrObject ( baseType , memberType , memberClass || ClassType . cloneAsInstantiable ( baseObj ) , errorNode , recursionCount + 1 , firstParamType || baseObj , isClassInstance ( baseType ) ) ; } if ( FunctionType . isClassMethod ( memberType ) || ( treatConstructorAsClassMember && FunctionType . isConstructorMethod ( memberType ) ) ) { const baseClass = isInstantiableClass ( baseType ) ? baseType : ClassType . cloneAsInstantiable ( baseType ) ; const effectiveFirstParamType = firstParamType ? isInstantiableClass ( baseType ) ? firstParamType : ( convertToInstantiable ( firstParamType ) as ClassType | TypeVarType ) : baseClass ; return partiallySpecializeFunctionForBoundClassOrObject ( TypeBase . isInstance ( baseType ) ? ClassType . cloneAsInstantiable ( baseType ) : baseType , memberType , memberClass || baseClass , errorNode , recursionCount + 1 , effectiveFirstParamType , true ) ; } if ( FunctionType . isStaticMethod ( memberType ) ) { const baseClass = isInstantiableClass ( baseType ) ? baseType : ClassType . cloneAsInstantiable ( baseType ) ; return partiallySpecializeFunctionForBoundClassOrObject ( TypeBase . isInstance ( baseType ) ? ClassType . cloneAsInstantiable ( baseType ) : baseType , memberType , memberClass || baseClass , errorNode , recursionCount + 1 , undefined , false ) ; } } else if ( isOverloadedFunction ( memberType ) ) { const newOverloadType = OverloadedFunctionType . create ( [ ] ) ; memberType . overloads . forEach ( ( overload ) => { if ( FunctionType . isOverloaded ( overload ) ) { const boundMethod = bindFunctionToClassOrObject ( baseType , overload , memberClass , undefined , recursionCount + 1 , treatConstructorAsClassMember , firstParamType ) ; if ( boundMethod ) { OverloadedFunctionType . addOverload ( newOverloadType , boundMethod as FunctionType ) ; } } } ) ; if ( newOverloadType . overloads . length === 1 ) { return newOverloadType . overloads [ 0 ] ; } else if ( newOverloadType . overloads . length === 0 ) { if ( errorNode ) { memberType . overloads . forEach ( ( overload ) => { bindFunctionToClassOrObject ( baseType , overload , memberClass , errorNode , recursionCount + 1 , treatConstructorAsClassMember , firstParamType ) ; } ) ; } return undefined ; } return newOverloadType ; } return memberType ; } function partiallySpecializeFunctionForBoundClassOrObject ( baseType , memberType , memberClass , errorNode , recursionCount , firstParamType , stripFirstParam = true ) { const typeVarMap = new TypeVarMap ( getTypeVarScopeId ( memberClass ) ) ; if ( firstParamType && memberType . details . parameters . length > 0 ) { const memberTypeFirstParam = memberType . details . parameters [ 0 ] ; const memberTypeFirstParamType = FunctionType . getEffectiveParameterType ( memberType , 0 ) ; const nonLiteralFirstParamType = stripLiteralValue ( firstParamType ) ; typeVarMap . addSolveForScope ( getTypeVarScopeId ( memberType ) ) ; const diag = new DiagnosticAddendum ( ) ; if ( isTypeVar ( memberTypeFirstParamType ) && memberTypeFirstParamType . details . boundType && isClassInstance ( memberTypeFirstParamType . details . boundType ) && ClassType . isProtocolClass ( memberTypeFirstParamType . details . boundType ) ) { if ( ! typeVarMap . isLocked ( ) ) { typeVarMap . setTypeVarType ( memberTypeFirstParamType , TypeBase . isInstantiable ( memberTypeFirstParamType ) ? convertToInstance ( nonLiteralFirstParamType ) : nonLiteralFirstParamType ) ; } } else if ( ! canAssignType ( memberTypeFirstParamType , nonLiteralFirstParamType , diag , typeVarMap , undefined , recursionCount + 1 ) ) { if ( memberTypeFirstParam . name && ! memberTypeFirstParam . isNameSynthesized && memberTypeFirstParam . hasDeclaredType ) { if ( errorNode ) { const methodName = memberType . details . name || '(unnamed)' ; addDiagnostic ( AnalyzerNodeInfo . getFileInfo ( errorNode ) . diagnosticRuleSet . reportGeneralTypeIssues , DiagnosticRule . reportGeneralTypeIssues , Localizer . Diagnostic . bindTypeMismatch ( ) . format ( { type : printType ( baseType ) , methodName : methodName , paramName : memberTypeFirstParam . name , } ) + diag . getString ( ) , errorNode ) ; } else { return undefined ; } } } } getFunctionEffectiveReturnType ( memberType ) ; const specializedFunction = applySolvedTypeVars ( memberType , typeVarMap ) as FunctionType ; return FunctionType . clone ( specializedFunction , stripFirstParam , baseType , getTypeVarScopeId ( baseType ) ) ; } function printObjectTypeForClass ( type ) { return TypePrinter . printObjectTypeForClass ( type , evaluatorOptions . printTypeFlags , getFunctionEffectiveReturnType ) ; } function printFunctionParts ( type ) { return TypePrinter . printFunctionParts ( type , evaluatorOptions . printTypeFlags , getFunctionEffectiveReturnType ) ; } function printType ( type , expandTypeAlias = false ) { let flags = evaluatorOptions . printTypeFlags ; if ( expandTypeAlias ) { flags |= TypePrinter . PrintTypeFlags . ExpandTypeAlias ; } return TypePrinter . printType ( type , flags , getFunctionEffectiveReturnType ) ; } function parseStringAsTypeAnnotation ( node ) { const fileInfo = AnalyzerNodeInfo . getFileInfo ( node ) ; const parser = new Parser ( ) ; const textValue = node . strings [ 0 ] . value ; const valueOffset = node . strings [ 0 ] . start + node . strings [ 0 ] . token . prefixLength + node . strings [ 0 ] . token . quoteMarkLength ; const parseOptions = new ParseOptions ( ) ; parseOptions . isStubFile = fileInfo . isStubFile ; parseOptions . pythonVersion = fileInfo . executionEnvironment . pythonVersion ; const parseResults = parser . parseTextExpression ( fileInfo . fileContents , valueOffset , textValue . length , parseOptions ) ; if ( parseResults . parseTree ) { parseResults . diagnostics . forEach ( ( diag ) => { addError ( diag . message , node ) ; } ) ; parseResults . parseTree . parent = node ; return parseResults . parseTree ; } return undefined ; } function narrowConstrainedTypeVar ( node , typeVar ) { const flowNode = AnalyzerNodeInfo . getFlowNode ( node ) ; if ( ! flowNode ) { return undefined ; } return codeFlowEngine . narrowConstrainedTypeVar ( flowNode , typeVar ) ; } const evaluatorInterface = { runWithCancellationToken , getType , getTypeOfExpression , getTypeOfAnnotation , getTypeOfClass , getTypeOfFunction , getTypeForExpressionExpectingType , getExpectedType , evaluateTypeForSubnode , evaluateTypesForStatement , evaluateTypesForMatchNode , evaluateTypesForCaseNode , evaluateTypeOfParameter , canBeTruthy , canBeFalsy , removeTruthinessFromType , removeFalsinessFromType , verifyRaiseExceptionType , verifyDeleteExpression , isAfterNodeReachable , isNodeReachable , isAsymmetricDescriptorAssignment , suppressDiagnostics , getDeclarationsForNameNode , getTypeForDeclaration , resolveAliasDeclaration , resolveAliasDeclarationWithInfo , getTypeFromIterable , getTypeFromIterator , getGetterTypeFromProperty , getTypeForArgument , markNamesAccessed , getScopeIdForNode , makeTopLevelTypeVarsConcrete , mapSubtypesExpandTypeVars , populateTypeVarMapBasedOnExpectedType , lookUpSymbolRecursive , getDeclaredTypeOfSymbol , getEffectiveTypeOfSymbol , getEffectiveTypeOfSymbolForUsage , getInferredTypeOfDeclaration , getDeclaredTypeForExpression , getFunctionDeclaredReturnType , getFunctionInferredReturnType , getBestOverloadForArguments , getBuiltInType , getTypeOfMember , getTypeFromObjectMember , getBoundMethod , getTypeFromMagicMethodReturn , bindFunctionToClassOrObject , getCallSignatureInfo , getTypeAnnotationForParameter , getAbstractMethods , narrowConstrainedTypeVar , canAssignType , canOverrideMethod , canAssignProtocolClassToSelf , assignTypeToExpression , getBuiltInObject , getTypingType , inferReturnTypeIfNecessary , addError , addWarning , addInformation , addUnusedCode , addDeprecated , addDiagnostic , addDiagnosticForTextRange , printType , printFunctionParts , getTypeCacheSize , useSpeculativeMode , setTypeForNode , checkForCancellation , } ; const codeFlowEngine = getCodeFlowEngine ( evaluatorInterface , speculativeTypeTracker ) ; return evaluatorInterface ; }