@zzzen/pyright-internal 1.2.0-dev.20261018 → 1.2.0-dev.20261108

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/dist/analyzer/binder.js +29 -12
  2. package/dist/analyzer/binder.js.map +1 -1
  3. package/dist/analyzer/checker.js +4 -0
  4. package/dist/analyzer/checker.js.map +1 -1
  5. package/dist/analyzer/codeFlowEngine.js +3 -3
  6. package/dist/analyzer/codeFlowEngine.js.map +1 -1
  7. package/dist/analyzer/constructorTransform.js +12 -0
  8. package/dist/analyzer/constructorTransform.js.map +1 -1
  9. package/dist/analyzer/constructors.d.ts +1 -1
  10. package/dist/analyzer/constructors.js +1 -1
  11. package/dist/analyzer/constructors.js.map +1 -1
  12. package/dist/analyzer/dataClasses.js +14 -5
  13. package/dist/analyzer/dataClasses.js.map +1 -1
  14. package/dist/analyzer/decorators.d.ts +2 -2
  15. package/dist/analyzer/decorators.js +22 -2
  16. package/dist/analyzer/decorators.js.map +1 -1
  17. package/dist/analyzer/functionTransform.d.ts +5 -0
  18. package/dist/analyzer/functionTransform.js +6 -3
  19. package/dist/analyzer/functionTransform.js.map +1 -1
  20. package/dist/analyzer/missingBindingMetadata.d.ts +6 -0
  21. package/dist/analyzer/missingBindingMetadata.js +22 -0
  22. package/dist/analyzer/missingBindingMetadata.js.map +1 -0
  23. package/dist/analyzer/namedTuples.d.ts +5 -1
  24. package/dist/analyzer/namedTuples.js +64 -35
  25. package/dist/analyzer/namedTuples.js.map +1 -1
  26. package/dist/analyzer/operations.js +45 -1
  27. package/dist/analyzer/operations.js.map +1 -1
  28. package/dist/analyzer/parseTreeUtils.d.ts +2 -0
  29. package/dist/analyzer/parseTreeUtils.js +43 -0
  30. package/dist/analyzer/parseTreeUtils.js.map +1 -1
  31. package/dist/analyzer/patternMatching.d.ts +5 -1
  32. package/dist/analyzer/patternMatching.js +6 -1
  33. package/dist/analyzer/patternMatching.js.map +1 -1
  34. package/dist/analyzer/program.d.ts +3 -0
  35. package/dist/analyzer/program.js +71 -1
  36. package/dist/analyzer/program.js.map +1 -1
  37. package/dist/analyzer/sentinel.js +7 -1
  38. package/dist/analyzer/sentinel.js.map +1 -1
  39. package/dist/analyzer/sourceFile.js +13 -6
  40. package/dist/analyzer/sourceFile.js.map +1 -1
  41. package/dist/analyzer/tupleComparison.d.ts +6 -0
  42. package/dist/analyzer/tupleComparison.js +731 -0
  43. package/dist/analyzer/tupleComparison.js.map +1 -0
  44. package/dist/analyzer/tuples.d.ts +1 -1
  45. package/dist/analyzer/tuples.js +35 -4
  46. package/dist/analyzer/tuples.js.map +1 -1
  47. package/dist/analyzer/typeCacheUtils.d.ts +1 -0
  48. package/dist/analyzer/typeCacheUtils.js +10 -0
  49. package/dist/analyzer/typeCacheUtils.js.map +1 -1
  50. package/dist/analyzer/typeEvaluator/boundMethodSpecialization.d.ts +15 -0
  51. package/dist/analyzer/typeEvaluator/boundMethodSpecialization.js +98 -0
  52. package/dist/analyzer/typeEvaluator/boundMethodSpecialization.js.map +1 -0
  53. package/dist/analyzer/typeEvaluator/classConstruction.d.ts +25 -0
  54. package/dist/analyzer/typeEvaluator/classConstruction.js +251 -0
  55. package/dist/analyzer/typeEvaluator/classConstruction.js.map +1 -0
  56. package/dist/analyzer/typeEvaluator/collectionInference.d.ts +41 -0
  57. package/dist/analyzer/typeEvaluator/collectionInference.js +695 -0
  58. package/dist/analyzer/typeEvaluator/collectionInference.js.map +1 -0
  59. package/dist/analyzer/typeEvaluator/diagnostics.d.ts +33 -0
  60. package/dist/analyzer/typeEvaluator/diagnostics.js +198 -0
  61. package/dist/analyzer/typeEvaluator/diagnostics.js.map +1 -0
  62. package/dist/analyzer/typeEvaluator/evaluatorCore.d.ts +80 -0
  63. package/dist/analyzer/typeEvaluator/evaluatorCore.js +1126 -0
  64. package/dist/analyzer/typeEvaluator/evaluatorCore.js.map +1 -0
  65. package/dist/analyzer/typeEvaluator/evaluatorNarrowing.d.ts +17 -0
  66. package/dist/analyzer/typeEvaluator/evaluatorNarrowing.js +370 -0
  67. package/dist/analyzer/typeEvaluator/evaluatorNarrowing.js.map +1 -0
  68. package/dist/analyzer/typeEvaluator/expressionEvaluation.d.ts +81 -0
  69. package/dist/analyzer/typeEvaluator/expressionEvaluation.js +1802 -0
  70. package/dist/analyzer/typeEvaluator/expressionEvaluation.js.map +1 -0
  71. package/dist/analyzer/typeEvaluator/flowAnalysis.d.ts +33 -0
  72. package/dist/analyzer/typeEvaluator/flowAnalysis.js +217 -0
  73. package/dist/analyzer/typeEvaluator/flowAnalysis.js.map +1 -0
  74. package/dist/analyzer/typeEvaluator/internals.d.ts +137 -0
  75. package/dist/analyzer/typeEvaluator/internals.js +10 -0
  76. package/dist/analyzer/typeEvaluator/internals.js.map +1 -0
  77. package/dist/analyzer/typeEvaluator/literalTypes.d.ts +3 -0
  78. package/dist/analyzer/typeEvaluator/literalTypes.js +52 -0
  79. package/dist/analyzer/typeEvaluator/literalTypes.js.map +1 -0
  80. package/dist/analyzer/typeEvaluator/memberResolution.d.ts +79 -0
  81. package/dist/analyzer/typeEvaluator/memberResolution.js +1007 -0
  82. package/dist/analyzer/typeEvaluator/memberResolution.js.map +1 -0
  83. package/dist/analyzer/typeEvaluator/overrideValidation.d.ts +15 -0
  84. package/dist/analyzer/typeEvaluator/overrideValidation.js +422 -0
  85. package/dist/analyzer/typeEvaluator/overrideValidation.js.map +1 -0
  86. package/dist/analyzer/typeEvaluator/returnTypeInference.d.ts +33 -0
  87. package/dist/analyzer/typeEvaluator/returnTypeInference.js +226 -0
  88. package/dist/analyzer/typeEvaluator/returnTypeInference.js.map +1 -0
  89. package/dist/analyzer/typeEvaluator/specialFormCreation.d.ts +39 -0
  90. package/dist/analyzer/typeEvaluator/specialFormCreation.js +1728 -0
  91. package/dist/analyzer/typeEvaluator/specialFormCreation.js.map +1 -0
  92. package/dist/analyzer/typeEvaluator/tupleUnpacking.d.ts +2 -0
  93. package/dist/analyzer/typeEvaluator/tupleUnpacking.js +36 -0
  94. package/dist/analyzer/typeEvaluator/tupleUnpacking.js.map +1 -0
  95. package/dist/analyzer/typeEvaluator/typeCompatibility.d.ts +36 -0
  96. package/dist/analyzer/typeEvaluator/typeCompatibility.js +1320 -0
  97. package/dist/analyzer/typeEvaluator/typeCompatibility.js.map +1 -0
  98. package/dist/analyzer/typeEvaluator/typeGuardNarrowing.d.ts +186 -0
  99. package/dist/analyzer/typeEvaluator/typeGuardNarrowing.js +1683 -0
  100. package/dist/analyzer/typeEvaluator/typeGuardNarrowing.js.map +1 -0
  101. package/dist/analyzer/typeEvaluator/typeVarHandling.d.ts +48 -0
  102. package/dist/analyzer/typeEvaluator/typeVarHandling.js +756 -0
  103. package/dist/analyzer/typeEvaluator/typeVarHandling.js.map +1 -0
  104. package/dist/analyzer/typeEvaluator.d.ts +3 -31
  105. package/dist/analyzer/typeEvaluator.js +5140 -13656
  106. package/dist/analyzer/typeEvaluator.js.map +1 -1
  107. package/dist/analyzer/typeEvaluatorTypes.d.ts +1 -1
  108. package/dist/analyzer/typeEvaluatorTypes.js +2 -3
  109. package/dist/analyzer/typeEvaluatorTypes.js.map +1 -1
  110. package/dist/analyzer/typeGuards.d.ts +3 -2
  111. package/dist/analyzer/typeGuards.js +236 -1375
  112. package/dist/analyzer/typeGuards.js.map +1 -1
  113. package/dist/analyzer/typeUtils.js +9 -2
  114. package/dist/analyzer/typeUtils.js.map +1 -1
  115. package/dist/analyzer/typedDicts.js +111 -0
  116. package/dist/analyzer/typedDicts.js.map +1 -1
  117. package/dist/analyzer/types.d.ts +14 -0
  118. package/dist/analyzer/types.js +215 -10
  119. package/dist/analyzer/types.js.map +1 -1
  120. package/dist/browser/browserConnection.d.ts +12 -0
  121. package/dist/browser/browserConnection.js +23 -0
  122. package/dist/browser/browserConnection.js.map +1 -0
  123. package/dist/browser/browserFileSystem.d.ts +73 -0
  124. package/dist/browser/browserFileSystem.js +578 -0
  125. package/dist/browser/browserFileSystem.js.map +1 -0
  126. package/dist/browser/browserHost.d.ts +4 -0
  127. package/dist/browser/browserHost.js +10 -0
  128. package/dist/browser/browserHost.js.map +1 -0
  129. package/dist/browser/browserProcess.d.ts +1 -0
  130. package/dist/browser/browserProcess.js +17 -0
  131. package/dist/browser/browserProcess.js.map +1 -0
  132. package/dist/browser/browserServer.d.ts +8 -0
  133. package/dist/browser/browserServer.js +32 -0
  134. package/dist/browser/browserServer.js.map +1 -0
  135. package/dist/browser/cancellation/common.d.ts +10 -0
  136. package/dist/browser/cancellation/common.js +114 -0
  137. package/dist/browser/cancellation/common.js.map +1 -0
  138. package/dist/browser/cancellation/objectURLReceiverStrategy.d.ts +5 -0
  139. package/dist/browser/cancellation/objectURLReceiverStrategy.js +37 -0
  140. package/dist/browser/cancellation/objectURLReceiverStrategy.js.map +1 -0
  141. package/dist/browser/cancellation/objectURLSenderStrategy.d.ts +7 -0
  142. package/dist/browser/cancellation/objectURLSenderStrategy.js +32 -0
  143. package/dist/browser/cancellation/objectURLSenderStrategy.js.map +1 -0
  144. package/dist/browser/worker.d.ts +1 -0
  145. package/dist/browser/worker.js +33 -0
  146. package/dist/browser/worker.js.map +1 -0
  147. package/dist/common/processUtils.d.ts +6 -0
  148. package/dist/common/processUtils.js +56 -1
  149. package/dist/common/processUtils.js.map +1 -1
  150. package/dist/common/textEditTracker.js +1 -1
  151. package/dist/common/textEditTracker.js.map +1 -1
  152. package/dist/common/windowsProcessTree.d.ts +2 -0
  153. package/dist/common/windowsProcessTree.js +23 -0
  154. package/dist/common/windowsProcessTree.js.map +1 -1
  155. package/dist/common/windowsProcessTree.json +23 -3
  156. package/dist/languageServerBase.d.ts +3 -0
  157. package/dist/languageServerBase.js +44 -12
  158. package/dist/languageServerBase.js.map +1 -1
  159. package/dist/languageService/callHierarchyProvider.js +6 -6
  160. package/dist/languageService/callHierarchyProvider.js.map +1 -1
  161. package/dist/languageService/referencesProvider.js +3 -3
  162. package/dist/languageService/referencesProvider.js.map +1 -1
  163. package/dist/languageService/renameProvider.js +1 -1
  164. package/dist/languageService/renameProvider.js.map +1 -1
  165. package/dist/languageService/symbolIndexer.js +2 -2
  166. package/dist/languageService/symbolIndexer.js.map +1 -1
  167. package/dist/localization/localize.d.ts +2 -0
  168. package/dist/localization/localize.js +2 -0
  169. package/dist/localization/localize.js.map +1 -1
  170. package/dist/localization/package.nls.en-us.json +8 -0
  171. package/dist/parser/parseTreeTokenReuse.d.ts +34 -0
  172. package/dist/parser/parseTreeTokenReuse.js +897 -0
  173. package/dist/parser/parseTreeTokenReuse.js.map +1 -0
  174. package/dist/parser/tokenizer.d.ts +10 -1
  175. package/dist/parser/tokenizer.js +184 -130
  176. package/dist/parser/tokenizer.js.map +1 -1
  177. package/dist/pyrightServer.d.ts +34 -0
  178. package/dist/pyrightServer.js +239 -0
  179. package/dist/pyrightServer.js.map +1 -0
  180. package/dist/server.d.ts +3 -23
  181. package/dist/server.js +12 -232
  182. package/dist/server.js.map +1 -1
  183. package/dist/tests/benchmarks/typeInferenceComparison.d.ts +1 -0
  184. package/dist/tests/benchmarks/typeInferenceComparison.js +1235 -0
  185. package/dist/tests/benchmarks/typeInferenceComparison.js.map +1 -0
  186. package/dist/tests/benchmarks/typeInferencePyrightEntry.d.ts +1 -0
  187. package/dist/tests/benchmarks/typeInferencePyrightEntry.js +53 -0
  188. package/dist/tests/benchmarks/typeInferencePyrightEntry.js.map +1 -0
  189. package/dist/tests/browserCancellation.test.d.ts +1 -0
  190. package/dist/tests/browserCancellation.test.js +63 -0
  191. package/dist/tests/browserCancellation.test.js.map +1 -0
  192. package/dist/tests/browserServer.test.d.ts +1 -0
  193. package/dist/tests/browserServer.test.js +177 -0
  194. package/dist/tests/browserServer.test.js.map +1 -0
  195. package/dist/tests/checker.test.js +8 -0
  196. package/dist/tests/checker.test.js.map +1 -1
  197. package/dist/tests/constraintSolver.test.js +45 -0
  198. package/dist/tests/constraintSolver.test.js.map +1 -1
  199. package/dist/tests/fourSlashParser.test.js +35 -0
  200. package/dist/tests/fourSlashParser.test.js.map +1 -1
  201. package/dist/tests/harness/fourslash/fourSlashParser.js +14 -4
  202. package/dist/tests/harness/fourslash/fourSlashParser.js.map +1 -1
  203. package/dist/tests/languageServer.test.js +15 -0
  204. package/dist/tests/languageServer.test.js.map +1 -1
  205. package/dist/tests/lsp/languageServer.js +6 -6
  206. package/dist/tests/lsp/languageServer.js.map +1 -1
  207. package/dist/tests/mypyPrimerAnalysis.test.js +148 -1
  208. package/dist/tests/mypyPrimerAnalysis.test.js.map +1 -1
  209. package/dist/tests/typeCacheUtils.test.js +46 -0
  210. package/dist/tests/typeCacheUtils.test.js.map +1 -1
  211. package/dist/tests/typeEvaluator1.test.js +78 -1
  212. package/dist/tests/typeEvaluator1.test.js.map +1 -1
  213. package/dist/tests/typeEvaluator2.test.js +54 -1
  214. package/dist/tests/typeEvaluator2.test.js.map +1 -1
  215. package/dist/tests/typeEvaluator3.test.js +4 -0
  216. package/dist/tests/typeEvaluator3.test.js.map +1 -1
  217. package/dist/tests/typeEvaluator4.test.js +42 -3
  218. package/dist/tests/typeEvaluator4.test.js.map +1 -1
  219. package/dist/tests/typeEvaluator6.test.js +35 -0
  220. package/dist/tests/typeEvaluator6.test.js.map +1 -1
  221. package/dist/tests/typeEvaluator7.test.js +414 -0
  222. package/dist/tests/typeEvaluator7.test.js.map +1 -1
  223. package/dist/tests/typeEvaluator8.test.js +1291 -1
  224. package/dist/tests/typeEvaluator8.test.js.map +1 -1
  225. package/dist/tests/typeUtils.test.js +28 -0
  226. package/dist/tests/typeUtils.test.js.map +1 -1
  227. package/dist/tests/types.test.js +55 -0
  228. package/dist/tests/types.test.js.map +1 -1
  229. package/dist/typeServer/programWrapper.js +8 -2
  230. package/dist/typeServer/programWrapper.js.map +1 -1
  231. package/dist/typeServer/server.d.ts +12 -2
  232. package/dist/typeServer/server.js +97 -0
  233. package/dist/typeServer/server.js.map +1 -1
  234. package/dist/typeServer/stubGenerator.js +136 -3
  235. package/dist/typeServer/stubGenerator.js.map +1 -1
  236. package/dist/typeServer/typeServerConversionUtils.js +13 -0
  237. package/dist/typeServer/typeServerConversionUtils.js.map +1 -1
  238. package/package.json +3 -1
@@ -43,6 +43,7 @@ var __importStar = (this && this.__importStar) || (function () {
43
43
  };
44
44
  })();
45
45
  Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.applyTypeNarrowingCallback = applyTypeNarrowingCallback;
46
47
  exports.getTypeNarrowingCallback = getTypeNarrowingCallback;
47
48
  exports.getIsInstanceClassTypes = getIsInstanceClassTypes;
48
49
  exports.narrowTypeForInstanceOrSubclass = narrowTypeForInstanceOrSubclass;
@@ -57,15 +58,94 @@ const parseNodes_1 = require("../parser/parseNodes");
57
58
  const analyzerNodeInfo_1 = require("./analyzerNodeInfo");
58
59
  const constraintSolver_1 = require("./constraintSolver");
59
60
  const constraintTracker_1 = require("./constraintTracker");
60
- const enums_1 = require("./enums");
61
- const operations_1 = require("./operations");
62
61
  const parameterUtils_1 = require("./parameterUtils");
63
62
  const ParseTreeUtils = __importStar(require("./parseTreeUtils"));
64
63
  const scopeUtils_1 = require("./scopeUtils");
65
64
  const symbol_1 = require("./symbol");
66
- const typedDicts_1 = require("./typedDicts");
65
+ const TypeEvaluatorNarrowing = __importStar(require("./typeEvaluator/typeGuardNarrowing"));
67
66
  const types_1 = require("./types");
68
67
  const typeUtils_1 = require("./typeUtils");
68
+ function applyTypeNarrowingCallback(callback, type) {
69
+ const result = callback(type);
70
+ const baseType = (0, types_1.getInferredTupleLiteralBase)(type);
71
+ if (baseType === type) {
72
+ return result;
73
+ }
74
+ // Narrow both views at the flow boundary, not recursively within a guard.
75
+ // Independently established literals must survive mutable inference too.
76
+ const baseResult = callback(baseType);
77
+ if (!result && !baseResult) {
78
+ return undefined;
79
+ }
80
+ return {
81
+ type: (0, types_1.retainInferredTupleLiterals)(result?.type ?? type, (0, types_1.getInferredTupleLiteralBase)(baseResult?.type ?? baseType)),
82
+ isIncomplete: !!result?.isIncomplete || !!baseResult?.isIncomplete,
83
+ };
84
+ }
85
+ function getEqualsNarrowingContext(evaluator) {
86
+ return {
87
+ getTypeOfExpression: (expression) => evaluator.getTypeOfExpression(expression),
88
+ isMatchingExpression: (reference, expression) => ParseTreeUtils.isMatchingExpression(reference, expression, (ref, expr) => isNameSameScope(evaluator, ref, expr)),
89
+ isMatchingExpressionOrWalrusRhs: (reference, expression) => isMatchingExpressionOrWalrusRhs(evaluator, reference, expression),
90
+ };
91
+ }
92
+ function getMemberAccessNarrowingContext(evaluator) {
93
+ return {
94
+ getTypeOfExpression: (expression) => evaluator.getTypeOfExpression(expression),
95
+ isMatchingExpression: (reference, expression) => ParseTreeUtils.isMatchingExpression(reference, expression, (ref, expr) => isNameSameScope(evaluator, ref, expr)),
96
+ };
97
+ }
98
+ function getLenComparisonNarrowingContext(evaluator) {
99
+ return {
100
+ getTypeOfExpression: (expression, flags) => evaluator.getTypeOfExpression(expression, flags),
101
+ isMatchingExpression: (reference, expression) => ParseTreeUtils.isMatchingExpression(reference, expression, (ref, expr) => isNameSameScope(evaluator, ref, expr)),
102
+ };
103
+ }
104
+ function getInOperatorNarrowingContext(evaluator) {
105
+ return {
106
+ getTypeOfExpression: (expression, flags) => evaluator.getTypeOfExpression(expression, flags),
107
+ isMatchingExpression: (reference, expression) => ParseTreeUtils.isMatchingExpression(reference, expression, (ref, expr) => isNameSameScope(evaluator, ref, expr)),
108
+ isMatchingExpressionOrWalrusRhs: (reference, expression) => isMatchingExpressionOrWalrusRhs(evaluator, reference, expression),
109
+ };
110
+ }
111
+ function getNoneEllipsisNarrowingContext(evaluator) {
112
+ return {
113
+ isMatchingExpression: (reference, expression) => ParseTreeUtils.isMatchingExpression(reference, expression, (ref, expr) => isNameSameScope(evaluator, ref, expr)),
114
+ isMatchingExpressionOrWalrusRhs: (reference, expression) => isMatchingExpressionOrWalrusRhs(evaluator, reference, expression),
115
+ };
116
+ }
117
+ function getTypeIsCallNarrowingContext(evaluator) {
118
+ return {
119
+ getTypeOfExpression: (expression, flags) => evaluator.getTypeOfExpression(expression, flags),
120
+ isMatchingExpressionOrWalrusRhs: (reference, expression) => isMatchingExpressionOrWalrusRhs(evaluator, reference, expression),
121
+ mapSubtypesExpandTypeVars: (type, callback) => evaluator.mapSubtypesExpandTypeVars(type, /* options */ undefined, callback),
122
+ };
123
+ }
124
+ function getIsLiteralOrClassNarrowingContext(evaluator) {
125
+ return {
126
+ getTypeOfExpression: (expression) => evaluator.getTypeOfExpression(expression),
127
+ isMatchingExpressionOrWalrusRhs: (reference, expression) => isMatchingExpressionOrWalrusRhs(evaluator, reference, expression),
128
+ };
129
+ }
130
+ function getIndexedLiteralNarrowingContext(evaluator) {
131
+ return {
132
+ getTypeOfExpression: (expression) => evaluator.getTypeOfExpression(expression),
133
+ isMatchingExpression: (reference, expression) => ParseTreeUtils.isMatchingExpression(reference, expression, (ref, expr) => isNameSameScope(evaluator, ref, expr)),
134
+ };
135
+ }
136
+ function getIsInstanceCallNarrowingContext(evaluator) {
137
+ return {
138
+ getTypeOfExpression: (expression, flags) => evaluator.getTypeOfExpression(expression, flags),
139
+ getIsInstanceClassTypes: (argType, argExpr) => getIsInstanceClassTypes(evaluator, argType, argExpr),
140
+ isMatchingExpressionOrWalrusRhs: (reference, expression) => isMatchingExpressionOrWalrusRhs(evaluator, reference, expression),
141
+ };
142
+ }
143
+ function getBoolCallNarrowingContext(evaluator) {
144
+ return {
145
+ getTypeOfExpression: (expression, flags) => evaluator.getTypeOfExpression(expression, flags),
146
+ isMatchingExpressionOrWalrusRhs: (reference, expression) => isMatchingExpressionOrWalrusRhs(evaluator, reference, expression),
147
+ };
148
+ }
69
149
  // Given a reference expression and a test expression, returns a callback that
70
150
  // can be used to narrow the type described by the reference expression.
71
151
  // If the specified flow node is not associated with the test expression,
@@ -81,394 +161,185 @@ function getTypeNarrowingCallback(evaluator, reference, testExpression, isPositi
81
161
  if (testExpression.nodeType === 7 /* ParseNodeType.BinaryOperation */) {
82
162
  const isOrIsNotOperator = testExpression.d.operator === 39 /* OperatorType.Is */ || testExpression.d.operator === 40 /* OperatorType.IsNot */;
83
163
  const equalsOrNotEqualsOperator = testExpression.d.operator === 12 /* OperatorType.Equals */ || testExpression.d.operator === 28 /* OperatorType.NotEquals */;
84
- const comparisonOperator = equalsOrNotEqualsOperator ||
85
- testExpression.d.operator === 20 /* OperatorType.LessThan */ ||
86
- testExpression.d.operator === 21 /* OperatorType.LessThanOrEqual */ ||
87
- testExpression.d.operator === 15 /* OperatorType.GreaterThan */ ||
88
- testExpression.d.operator === 16 /* OperatorType.GreaterThanOrEqual */;
89
164
  if (isOrIsNotOperator || equalsOrNotEqualsOperator) {
90
- // Invert the "isPositiveTest" value if this is an "is not" operation.
91
- const adjIsPositiveTest = testExpression.d.operator === 39 /* OperatorType.Is */ || testExpression.d.operator === 12 /* OperatorType.Equals */
92
- ? isPositiveTest
93
- : !isPositiveTest;
94
- // Look for "X is None", "X is not None", "X == None", and "X != None".
95
- // These are commonly-used patterns used in control flow.
96
- if (testExpression.d.rightExpr.nodeType === 14 /* ParseNodeType.Constant */ &&
97
- testExpression.d.rightExpr.d.constType === 27 /* KeywordType.None */) {
98
- // Allow the LHS to be a simple expression or an assignment expression.
99
- // For assignment expressions, narrow both the target and the RHS
100
- // (consistent with truthiness narrowing).
101
- if (isMatchingExpressionOrWalrusRhs(evaluator, reference, testExpression.d.leftExpr)) {
165
+ const noneEllipsisInfo = TypeEvaluatorNarrowing.getNoneEllipsisNarrowingInfo(getNoneEllipsisNarrowingContext(evaluator), reference, testExpression, isPositiveTest);
166
+ if (noneEllipsisInfo) {
167
+ if (noneEllipsisInfo.kind === 'none') {
102
168
  return (type) => {
103
- return { type: narrowTypeForIsNone(evaluator, type, adjIsPositiveTest), isIncomplete: false };
104
- };
105
- }
106
- const leftExpression = testExpression.d.leftExpr;
107
- if (leftExpression.nodeType === 27 /* ParseNodeType.Index */ &&
108
- ParseTreeUtils.isMatchingExpression(reference, leftExpression.d.leftExpr, (ref, expr) => isNameSameScope(evaluator, ref, expr)) &&
109
- leftExpression.d.items.length === 1 &&
110
- !leftExpression.d.trailingComma &&
111
- leftExpression.d.items[0].d.argCategory === 0 /* ArgCategory.Simple */ &&
112
- !leftExpression.d.items[0].d.name &&
113
- leftExpression.d.items[0].d.valueExpr.nodeType === 40 /* ParseNodeType.Number */ &&
114
- leftExpression.d.items[0].d.valueExpr.d.isInteger &&
115
- !leftExpression.d.items[0].d.valueExpr.d.isImaginary) {
116
- const indexValue = leftExpression.d.items[0].d.valueExpr.d.value;
117
- if (typeof indexValue === 'number') {
118
- return (type) => {
119
- return {
120
- type: narrowTupleTypeForIsNone(evaluator, type, adjIsPositiveTest, indexValue),
121
- isIncomplete: false,
122
- };
169
+ return {
170
+ type: narrowTypeForIsNone(evaluator, type, noneEllipsisInfo.adjIsPositiveTest),
171
+ isIncomplete: false,
123
172
  };
124
- }
173
+ };
125
174
  }
126
- }
127
- // Look for "X is ...", "X is not ...", "X == ...", and "X != ...".
128
- if (testExpression.d.rightExpr.nodeType === 21 /* ParseNodeType.Ellipsis */) {
129
- if (isMatchingExpressionOrWalrusRhs(evaluator, reference, testExpression.d.leftExpr)) {
175
+ if (noneEllipsisInfo.kind === 'tuple-none') {
130
176
  return (type) => {
131
177
  return {
132
- type: narrowTypeForIsEllipsis(evaluator, testExpression, type, adjIsPositiveTest),
178
+ type: narrowTupleTypeForIsNone(evaluator, type, noneEllipsisInfo.adjIsPositiveTest, noneEllipsisInfo.tupleIndex),
133
179
  isIncomplete: false,
134
180
  };
135
181
  };
136
182
  }
183
+ return (type) => {
184
+ return {
185
+ type: narrowTypeForIsEllipsis(evaluator, testExpression, type, noneEllipsisInfo.adjIsPositiveTest),
186
+ isIncomplete: false,
187
+ };
188
+ };
137
189
  }
138
- // Look for "type(X) is Y", "type(X) is not Y", "type(X) == Y" or "type(X) != Y".
139
- if (testExpression.d.leftExpr.nodeType === 9 /* ParseNodeType.Call */) {
140
- if (testExpression.d.leftExpr.d.args.length === 1 &&
141
- testExpression.d.leftExpr.d.args[0].d.argCategory === 0 /* ArgCategory.Simple */) {
142
- const arg0Expr = testExpression.d.leftExpr.d.args[0].d.valueExpr;
143
- if (isMatchingExpressionOrWalrusRhs(evaluator, reference, arg0Expr)) {
144
- const callType = evaluator.getTypeOfExpression(testExpression.d.leftExpr.d.leftExpr, 2 /* EvalFlags.CallBaseDefaults */).type;
145
- if ((0, types_1.isInstantiableClass)(callType) && types_1.ClassType.isBuiltIn(callType, 'type')) {
146
- const rhsResult = evaluator.getTypeOfExpression(testExpression.d.rightExpr);
147
- const classTypes = [];
148
- let isClassType = true;
149
- evaluator.mapSubtypesExpandTypeVars(rhsResult.type,
150
- /* options */ undefined, (expandedSubtype) => {
151
- if ((0, types_1.isInstantiableClass)(expandedSubtype)) {
152
- classTypes.push(expandedSubtype);
153
- }
154
- else {
155
- isClassType = false;
156
- }
157
- return undefined;
158
- });
159
- if (isClassType && classTypes.length > 0) {
160
- return (type) => {
161
- return {
162
- type: narrowTypeForTypeIs(evaluator, type, classTypes, adjIsPositiveTest),
163
- isIncomplete: !!rhsResult.isIncomplete,
164
- };
165
- };
166
- }
167
- }
168
- }
169
- }
190
+ const typeIsCallInfo = TypeEvaluatorNarrowing.getTypeIsCallNarrowingInfo(getTypeIsCallNarrowingContext(evaluator), reference, testExpression, isPositiveTest);
191
+ if (typeIsCallInfo) {
192
+ return (type) => {
193
+ return {
194
+ type: narrowTypeForTypeIs(evaluator, type, typeIsCallInfo.classTypes, typeIsCallInfo.adjIsPositiveTest, typeIsCallInfo.isOrIsNotOperator, typeIsCallInfo.classTypeVar, typeIsCallInfo.allowLegacyEquality),
195
+ isIncomplete: typeIsCallInfo.isIncomplete,
196
+ };
197
+ };
170
198
  }
171
199
  if (isOrIsNotOperator) {
172
- if (isMatchingExpressionOrWalrusRhs(evaluator, reference, testExpression.d.leftExpr)) {
173
- const rightTypeResult = evaluator.getTypeOfExpression(testExpression.d.rightExpr);
174
- const rightType = rightTypeResult.type;
175
- // Look for "X is Y" or "X is not Y" where Y is a literal.
176
- if ((0, types_1.isClassInstance)(rightType) && rightType.priv.literalValue !== undefined) {
200
+ const isLiteralOrClassInfo = TypeEvaluatorNarrowing.getIsLiteralOrClassNarrowingInfo(getIsLiteralOrClassNarrowingContext(evaluator), reference, testExpression, isPositiveTest);
201
+ if (isLiteralOrClassInfo) {
202
+ if (isLiteralOrClassInfo.kind === 'literal') {
177
203
  return (type) => {
178
204
  return {
179
- type: narrowTypeForLiteralComparison(evaluator, type, rightType, adjIsPositiveTest,
205
+ type: narrowTypeForLiteralComparison(evaluator, type, isLiteralOrClassInfo.rightType, isLiteralOrClassInfo.adjIsPositiveTest,
180
206
  /* isIsOperator */ true),
181
- isIncomplete: !!rightTypeResult.isIncomplete,
207
+ isIncomplete: isLiteralOrClassInfo.isIncomplete,
182
208
  };
183
209
  };
184
210
  }
185
- // Look for X is <class> or X is not <class>.
186
- if ((0, types_1.isInstantiableClass)(rightType)) {
187
- return (type) => {
188
- return {
189
- type: narrowTypeForClassComparison(evaluator, type, rightType, adjIsPositiveTest),
190
- isIncomplete: !!rightTypeResult.isIncomplete,
191
- };
211
+ return (type) => {
212
+ return {
213
+ type: narrowTypeForClassComparison(evaluator, type, isLiteralOrClassInfo.rightType, isLiteralOrClassInfo.adjIsPositiveTest),
214
+ isIncomplete: isLiteralOrClassInfo.isIncomplete,
192
215
  };
193
- }
194
- }
195
- // Look for X[<literal>] is <literal> or X[<literal>] is not <literal>.
196
- if (testExpression.d.leftExpr.nodeType === 27 /* ParseNodeType.Index */ &&
197
- testExpression.d.leftExpr.d.items.length === 1 &&
198
- !testExpression.d.leftExpr.d.trailingComma &&
199
- testExpression.d.leftExpr.d.items[0].d.argCategory === 0 /* ArgCategory.Simple */ &&
200
- ParseTreeUtils.isMatchingExpression(reference, testExpression.d.leftExpr.d.leftExpr, (ref, expr) => isNameSameScope(evaluator, ref, expr))) {
201
- const indexTypeResult = evaluator.getTypeOfExpression(testExpression.d.leftExpr.d.items[0].d.valueExpr);
202
- const indexType = indexTypeResult.type;
203
- if ((0, types_1.isClassInstance)(indexType) && (0, typeUtils_1.isLiteralType)(indexType)) {
204
- if (types_1.ClassType.isBuiltIn(indexType, 'str')) {
205
- const rightType = evaluator.getTypeOfExpression(testExpression.d.rightExpr).type;
206
- if ((0, types_1.isClassInstance)(rightType) && rightType.priv.literalValue !== undefined) {
207
- return (type) => {
208
- return {
209
- type: narrowTypeForDiscriminatedDictEntryComparison(evaluator, type, indexType, rightType, adjIsPositiveTest),
210
- isIncomplete: !!indexTypeResult.isIncomplete,
211
- };
212
- };
213
- }
214
- }
215
- else if (types_1.ClassType.isBuiltIn(indexType, 'int')) {
216
- const rightTypeResult = evaluator.getTypeOfExpression(testExpression.d.rightExpr);
217
- const rightType = rightTypeResult.type;
218
- if ((0, types_1.isClassInstance)(rightType) && rightType.priv.literalValue !== undefined) {
219
- let canNarrow = false;
220
- // Narrowing can be applied only for bool or enum literals.
221
- if (types_1.ClassType.isBuiltIn(rightType, 'bool')) {
222
- canNarrow = true;
223
- }
224
- else if (rightType.priv.literalValue instanceof types_1.EnumLiteral) {
225
- canNarrow = true;
226
- }
227
- if (canNarrow) {
228
- return (type) => {
229
- return {
230
- type: narrowTypeForDiscriminatedTupleComparison(evaluator, type, indexType, rightType, adjIsPositiveTest),
231
- isIncomplete: !!rightTypeResult.isIncomplete,
232
- };
233
- };
234
- }
235
- }
236
- }
237
- }
216
+ };
238
217
  }
239
- }
240
- if (equalsOrNotEqualsOperator) {
241
- // Look for X == <literal> or X != <literal>
242
- const adjIsPositiveTest = testExpression.d.operator === 12 /* OperatorType.Equals */ ? isPositiveTest : !isPositiveTest;
243
- if (isMatchingExpressionOrWalrusRhs(evaluator, reference, testExpression.d.leftExpr)) {
244
- const rightTypeResult = evaluator.getTypeOfExpression(testExpression.d.rightExpr);
245
- const rightType = rightTypeResult.type;
246
- if ((0, types_1.isClassInstance)(rightType) && rightType.priv.literalValue !== undefined) {
218
+ const indexedLiteralInfo = TypeEvaluatorNarrowing.getIndexedLiteralNarrowingInfo(getIndexedLiteralNarrowingContext(evaluator), reference, testExpression, isPositiveTest);
219
+ if (indexedLiteralInfo) {
220
+ if (indexedLiteralInfo.kind === 'dict') {
247
221
  return (type) => {
248
222
  return {
249
- type: narrowTypeForLiteralComparison(evaluator, type, rightType, adjIsPositiveTest,
250
- /* isIsOperator */ false),
251
- isIncomplete: !!rightTypeResult.isIncomplete,
223
+ type: narrowTypeForDiscriminatedDictEntryComparison(evaluator, type, indexedLiteralInfo.indexType, indexedLiteralInfo.rightType, indexedLiteralInfo.adjIsPositiveTest),
224
+ isIncomplete: indexedLiteralInfo.isIncomplete,
252
225
  };
253
226
  };
254
227
  }
255
- // Look for X == <class> or X != <class>.
256
- if ((0, types_1.isInstantiableClass)(rightType)) {
257
- return (type) => {
258
- return {
259
- type: narrowTypeForClassComparison(evaluator, type, rightType, adjIsPositiveTest,
260
- /* isIsOperator */ false),
261
- isIncomplete: !!rightTypeResult.isIncomplete,
262
- };
228
+ return (type) => {
229
+ return {
230
+ type: narrowTypeForDiscriminatedTupleComparison(evaluator, type, indexedLiteralInfo.indexType, indexedLiteralInfo.rightType, indexedLiteralInfo.adjIsPositiveTest),
231
+ isIncomplete: indexedLiteralInfo.isIncomplete,
263
232
  };
264
- }
265
- }
266
- // Look for X[<literal>] == <literal> or X[<literal>] != <literal>
267
- if (testExpression.d.leftExpr.nodeType === 27 /* ParseNodeType.Index */ &&
268
- testExpression.d.leftExpr.d.items.length === 1 &&
269
- !testExpression.d.leftExpr.d.trailingComma &&
270
- testExpression.d.leftExpr.d.items[0].d.argCategory === 0 /* ArgCategory.Simple */ &&
271
- ParseTreeUtils.isMatchingExpression(reference, testExpression.d.leftExpr.d.leftExpr, (ref, expr) => isNameSameScope(evaluator, ref, expr))) {
272
- const indexTypeResult = evaluator.getTypeOfExpression(testExpression.d.leftExpr.d.items[0].d.valueExpr);
273
- const indexType = indexTypeResult.type;
274
- if ((0, types_1.isClassInstance)(indexType) && (0, typeUtils_1.isLiteralType)(indexType)) {
275
- if (types_1.ClassType.isBuiltIn(indexType, ['str', 'int'])) {
276
- const rightTypeResult = evaluator.getTypeOfExpression(testExpression.d.rightExpr);
277
- const rightType = rightTypeResult.type;
278
- if ((0, typeUtils_1.isLiteralTypeOrUnion)(rightType)) {
279
- return (type) => {
280
- let narrowedType;
281
- if (types_1.ClassType.isBuiltIn(indexType, 'str')) {
282
- narrowedType = narrowTypeForDiscriminatedDictEntryComparison(evaluator, type, indexType, rightType, adjIsPositiveTest);
283
- }
284
- else {
285
- narrowedType = narrowTypeForDiscriminatedTupleComparison(evaluator, type, indexType, rightType, adjIsPositiveTest);
286
- }
287
- return {
288
- type: narrowedType,
289
- isIncomplete: !!indexTypeResult.isIncomplete || !!rightTypeResult.isIncomplete,
290
- };
291
- };
292
- }
293
- }
294
- }
233
+ };
295
234
  }
296
235
  }
297
- // Look for X.Y == <literal> or X.Y != <literal>
298
- if (equalsOrNotEqualsOperator &&
299
- testExpression.d.leftExpr.nodeType === 35 /* ParseNodeType.MemberAccess */ &&
300
- ParseTreeUtils.isMatchingExpression(reference, testExpression.d.leftExpr.d.leftExpr, (ref, expr) => isNameSameScope(evaluator, ref, expr))) {
301
- const rightTypeResult = evaluator.getTypeOfExpression(testExpression.d.rightExpr);
302
- const rightType = rightTypeResult.type;
303
- const memberName = testExpression.d.leftExpr.d.member;
304
- if ((0, types_1.isClassInstance)(rightType)) {
305
- if (rightType.priv.literalValue !== undefined || (0, typeUtils_1.isNoneInstance)(rightType)) {
306
- return (type) => {
307
- return {
308
- type: narrowTypeForDiscriminatedLiteralFieldComparison(evaluator, type, memberName.d.value, rightType, adjIsPositiveTest),
309
- isIncomplete: !!rightTypeResult.isIncomplete,
310
- };
236
+ const equalsInfo = TypeEvaluatorNarrowing.getEqualsNarrowingInfo(getEqualsNarrowingContext(evaluator), reference, testExpression, isPositiveTest);
237
+ if (equalsInfo) {
238
+ if (equalsInfo.kind === 'literal') {
239
+ return (type) => {
240
+ return {
241
+ type: narrowTypeForLiteralComparison(evaluator, type, equalsInfo.rightType, equalsInfo.adjIsPositiveTest,
242
+ /* isIsOperator */ false),
243
+ isIncomplete: equalsInfo.isIncomplete,
311
244
  };
312
- }
245
+ };
313
246
  }
314
- }
315
- // Look for X.Y is <literal> or X.Y is not <literal> where <literal> is
316
- // an enum or bool literal
317
- if (testExpression.d.leftExpr.nodeType === 35 /* ParseNodeType.MemberAccess */ &&
318
- ParseTreeUtils.isMatchingExpression(reference, testExpression.d.leftExpr.d.leftExpr, (ref, expr) => isNameSameScope(evaluator, ref, expr))) {
319
- const rightTypeResult = evaluator.getTypeOfExpression(testExpression.d.rightExpr);
320
- const rightType = rightTypeResult.type;
321
- const memberName = testExpression.d.leftExpr.d.member;
322
- if ((0, types_1.isClassInstance)(rightType) &&
323
- (types_1.ClassType.isEnumClass(rightType) || types_1.ClassType.isBuiltIn(rightType, 'bool')) &&
324
- rightType.priv.literalValue !== undefined) {
247
+ if (equalsInfo.kind === 'class') {
325
248
  return (type) => {
326
249
  return {
327
- type: narrowTypeForDiscriminatedLiteralFieldComparison(evaluator, type, memberName.d.value, rightType, adjIsPositiveTest),
328
- isIncomplete: !!rightTypeResult.isIncomplete,
250
+ type: narrowTypeForClassComparison(evaluator, type, equalsInfo.rightType, equalsInfo.adjIsPositiveTest,
251
+ /* isIsOperator */ false),
252
+ isIncomplete: equalsInfo.isIncomplete,
329
253
  };
330
254
  };
331
255
  }
332
- }
333
- // Look for X.Y is None or X.Y is not None
334
- // These are commonly-used patterns used in control flow.
335
- if (testExpression.d.leftExpr.nodeType === 35 /* ParseNodeType.MemberAccess */ &&
336
- ParseTreeUtils.isMatchingExpression(reference, testExpression.d.leftExpr.d.leftExpr, (ref, expr) => isNameSameScope(evaluator, ref, expr)) &&
337
- testExpression.d.rightExpr.nodeType === 14 /* ParseNodeType.Constant */ &&
338
- testExpression.d.rightExpr.d.constType === 27 /* KeywordType.None */) {
339
- const memberName = testExpression.d.leftExpr.d.member;
340
256
  return (type) => {
257
+ let narrowedType;
258
+ const indexType = equalsInfo.indexType;
259
+ if (types_1.ClassType.isBuiltIn(indexType, 'str')) {
260
+ narrowedType = narrowTypeForDiscriminatedDictEntryComparison(evaluator, type, indexType, equalsInfo.rightType, equalsInfo.adjIsPositiveTest);
261
+ }
262
+ else {
263
+ narrowedType = narrowTypeForDiscriminatedTupleComparison(evaluator, type, indexType, equalsInfo.rightType, equalsInfo.adjIsPositiveTest);
264
+ }
341
265
  return {
342
- type: narrowTypeForDiscriminatedFieldNoneComparison(evaluator, type, memberName.d.value, adjIsPositiveTest),
343
- isIncomplete: false,
266
+ type: narrowedType,
267
+ isIncomplete: equalsInfo.isIncomplete,
344
268
  };
345
269
  };
346
270
  }
347
- }
348
- // Look for len(x) == <literal>, len(x) != <literal>, len(x) < <literal>, etc.
349
- if (comparisonOperator &&
350
- testExpression.d.leftExpr.nodeType === 9 /* ParseNodeType.Call */ &&
351
- testExpression.d.leftExpr.d.args.length === 1) {
352
- const arg0Expr = testExpression.d.leftExpr.d.args[0].d.valueExpr;
353
- if (ParseTreeUtils.isMatchingExpression(reference, arg0Expr, (ref, expr) => isNameSameScope(evaluator, ref, expr))) {
354
- const callTypeResult = evaluator.getTypeOfExpression(testExpression.d.leftExpr.d.leftExpr, 2 /* EvalFlags.CallBaseDefaults */);
355
- const callType = callTypeResult.type;
356
- if ((0, types_1.isFunction)(callType) && callType.shared.fullName === 'builtins.len') {
357
- const rightTypeResult = evaluator.getTypeOfExpression(testExpression.d.rightExpr);
358
- const rightType = rightTypeResult.type;
359
- if ((0, types_1.isClassInstance)(rightType) &&
360
- typeof rightType.priv.literalValue === 'number' &&
361
- rightType.priv.literalValue >= 0) {
362
- let tupleLength = rightType.priv.literalValue;
363
- // We'll treat <, <= and == as positive tests with >=, > and != as
364
- // their negative counterparts.
365
- const isLessOrEqual = testExpression.d.operator === 12 /* OperatorType.Equals */ ||
366
- testExpression.d.operator === 20 /* OperatorType.LessThan */ ||
367
- testExpression.d.operator === 21 /* OperatorType.LessThanOrEqual */;
368
- const adjIsPositiveTest = isLessOrEqual ? isPositiveTest : !isPositiveTest;
369
- // For <= (or its negative counterpart >), adjust the tuple length by 1.
370
- if (testExpression.d.operator === 21 /* OperatorType.LessThanOrEqual */ ||
371
- testExpression.d.operator === 15 /* OperatorType.GreaterThan */) {
372
- tupleLength++;
373
- }
374
- const isEqualityCheck = testExpression.d.operator === 12 /* OperatorType.Equals */ ||
375
- testExpression.d.operator === 28 /* OperatorType.NotEquals */;
376
- return (type) => {
377
- return {
378
- type: narrowTypeForTupleLength(evaluator, type, tupleLength, adjIsPositiveTest, !isEqualityCheck),
379
- isIncomplete: !!callTypeResult.isIncomplete || !!rightTypeResult.isIncomplete,
380
- };
271
+ const memberAccessInfo = TypeEvaluatorNarrowing.getMemberAccessNarrowingInfo(getMemberAccessNarrowingContext(evaluator), reference, testExpression, isPositiveTest);
272
+ if (memberAccessInfo) {
273
+ if (memberAccessInfo.kind === 'none') {
274
+ return (type) => {
275
+ return {
276
+ type: narrowTypeForDiscriminatedFieldNoneComparison(evaluator, type, memberAccessInfo.memberName, memberAccessInfo.adjIsPositiveTest),
277
+ isIncomplete: false,
381
278
  };
382
- }
279
+ };
383
280
  }
384
- }
385
- }
386
- if (testExpression.d.operator === 41 /* OperatorType.In */ || testExpression.d.operator === 42 /* OperatorType.NotIn */) {
387
- // Look for "x in y" or "x not in y" where y is one of several built-in types.
388
- if (isMatchingExpressionOrWalrusRhs(evaluator, reference, testExpression.d.leftExpr)) {
389
- const rightTypeResult = evaluator.getTypeOfExpression(testExpression.d.rightExpr);
390
- const rightType = rightTypeResult.type;
391
- const adjIsPositiveTest = testExpression.d.operator === 41 /* OperatorType.In */ ? isPositiveTest : !isPositiveTest;
392
281
  return (type) => {
393
282
  return {
394
- type: narrowTypeForContainerType(evaluator, type, rightType, adjIsPositiveTest),
395
- isIncomplete: !!rightTypeResult.isIncomplete,
283
+ type: narrowTypeForDiscriminatedLiteralFieldComparison(evaluator, type, memberAccessInfo.memberName, memberAccessInfo.rightType, memberAccessInfo.adjIsPositiveTest),
284
+ isIncomplete: memberAccessInfo.isIncomplete,
396
285
  };
397
286
  };
398
287
  }
399
- if (ParseTreeUtils.isMatchingExpression(reference, testExpression.d.rightExpr, (ref, expr) => isNameSameScope(evaluator, ref, expr))) {
400
- // Look for <string literal> in y where y is a union that contains
401
- // one or more TypedDicts.
402
- const leftTypeResult = evaluator.getTypeOfExpression(testExpression.d.leftExpr);
403
- const leftType = leftTypeResult.type;
404
- if ((0, types_1.isClassInstance)(leftType) && types_1.ClassType.isBuiltIn(leftType, 'str') && (0, typeUtils_1.isLiteralType)(leftType)) {
405
- const adjIsPositiveTest = testExpression.d.operator === 41 /* OperatorType.In */ ? isPositiveTest : !isPositiveTest;
406
- return (type) => {
407
- return {
408
- type: narrowTypeForTypedDictKey(evaluator, type, types_1.ClassType.cloneAsInstantiable(leftType), adjIsPositiveTest),
409
- isIncomplete: !!leftTypeResult.isIncomplete,
410
- };
288
+ }
289
+ const lenComparisonInfo = TypeEvaluatorNarrowing.getLenComparisonNarrowingInfo(getLenComparisonNarrowingContext(evaluator), reference, testExpression, isPositiveTest);
290
+ if (lenComparisonInfo) {
291
+ return (type) => {
292
+ return {
293
+ type: narrowTypeForTupleLength(evaluator, type, lenComparisonInfo.tupleLength, lenComparisonInfo.adjIsPositiveTest, lenComparisonInfo.isLessThanCheck),
294
+ isIncomplete: lenComparisonInfo.isIncomplete,
295
+ };
296
+ };
297
+ }
298
+ const inOperatorInfo = TypeEvaluatorNarrowing.getInOperatorNarrowingInfo(getInOperatorNarrowingContext(evaluator), reference, testExpression, isPositiveTest);
299
+ if (inOperatorInfo) {
300
+ if (inOperatorInfo.kind === 'container') {
301
+ return (type) => {
302
+ return {
303
+ type: narrowTypeForContainerType(evaluator, type, inOperatorInfo.containerType, inOperatorInfo.adjIsPositiveTest),
304
+ isIncomplete: inOperatorInfo.isIncomplete,
411
305
  };
412
- }
306
+ };
413
307
  }
308
+ return (type) => {
309
+ return {
310
+ type: narrowTypeForTypedDictKey(evaluator, type, inOperatorInfo.typedDictKeyType, inOperatorInfo.adjIsPositiveTest),
311
+ isIncomplete: inOperatorInfo.isIncomplete,
312
+ };
313
+ };
414
314
  }
415
315
  }
416
316
  if (testExpression.nodeType === 9 /* ParseNodeType.Call */) {
417
- // Look for "isinstance(X, Y)" or "issubclass(X, Y)".
418
- if (testExpression.d.args.length === 2) {
419
- // Make sure the first parameter is a supported expression type
420
- // and the second parameter is a valid class type or a tuple
421
- // of valid class types.
422
- const arg0Expr = testExpression.d.args[0].d.valueExpr;
423
- const arg1Expr = testExpression.d.args[1].d.valueExpr;
424
- if (isMatchingExpressionOrWalrusRhs(evaluator, reference, arg0Expr)) {
425
- const callTypeResult = evaluator.getTypeOfExpression(testExpression.d.leftExpr, 2 /* EvalFlags.CallBaseDefaults */);
426
- const callType = callTypeResult.type;
427
- if ((0, types_1.isFunction)(callType) && types_1.FunctionType.isBuiltIn(callType, ['isinstance', 'issubclass'])) {
428
- const isInstanceCheck = types_1.FunctionType.isBuiltIn(callType, 'isinstance');
429
- const arg1TypeResult = evaluator.getTypeOfExpression(arg1Expr, 536871546 /* EvalFlags.IsInstanceArgDefaults */);
430
- const arg1Type = arg1TypeResult.type;
431
- const classTypeInfo = getIsInstanceClassTypes(evaluator, arg1Type, arg1Expr);
432
- const isIncomplete = !!callTypeResult.isIncomplete || !!arg1TypeResult.isIncomplete;
433
- if (classTypeInfo) {
434
- const classTypeList = isPositiveTest
435
- ? classTypeInfo.classTypes
436
- : classTypeInfo.negativeClassTypes;
437
- return (type) => {
438
- return {
439
- type: narrowTypeForInstanceOrSubclass(evaluator, type, classTypeList, isInstanceCheck,
440
- /* isTypeIsCheck */ false, isPositiveTest, testExpression, nodeInfo),
441
- isIncomplete,
442
- };
443
- };
444
- }
445
- else if (isIncomplete) {
446
- // If the type is incomplete, it may include unknowns, which will result
447
- // in classTypeList being undefined.
448
- return (type) => {
449
- return {
450
- type,
451
- isIncomplete: true,
452
- };
453
- };
454
- }
455
- }
456
- }
457
- }
458
- // Look for "bool(X)"
459
- if (testExpression.d.args.length === 1 && !testExpression.d.args[0].d.name) {
460
- if (isMatchingExpressionOrWalrusRhs(evaluator, reference, testExpression.d.args[0].d.valueExpr)) {
461
- const callTypeResult = evaluator.getTypeOfExpression(testExpression.d.leftExpr, 2 /* EvalFlags.CallBaseDefaults */);
462
- const callType = callTypeResult.type;
463
- if ((0, types_1.isInstantiableClass)(callType) && types_1.ClassType.isBuiltIn(callType, 'bool')) {
464
- return (type) => {
465
- return {
466
- type: narrowTypeForTruthiness(evaluator, type, isPositiveTest),
467
- isIncomplete: !!callTypeResult.isIncomplete,
468
- };
317
+ const isInstanceInfo = TypeEvaluatorNarrowing.getIsInstanceCallNarrowingInfo(getIsInstanceCallNarrowingContext(evaluator), reference, testExpression, isPositiveTest);
318
+ if (isInstanceInfo) {
319
+ if (isInstanceInfo.kind === 'narrow') {
320
+ return (type) => {
321
+ return {
322
+ type: narrowTypeForInstanceOrSubclass(evaluator, type, isInstanceInfo.classTypeList, isInstanceInfo.isInstanceCheck,
323
+ /* isTypeIsCheck */ false, isPositiveTest, testExpression, nodeInfo),
324
+ isIncomplete: isInstanceInfo.isIncomplete,
469
325
  };
470
- }
326
+ };
471
327
  }
328
+ return (type) => {
329
+ return {
330
+ type,
331
+ isIncomplete: true,
332
+ };
333
+ };
334
+ }
335
+ const boolCallInfo = TypeEvaluatorNarrowing.getBoolCallNarrowingInfo(getBoolCallNarrowingContext(evaluator), reference, testExpression);
336
+ if (boolCallInfo) {
337
+ return (type) => {
338
+ return {
339
+ type: narrowTypeForTruthiness(evaluator, type, isPositiveTest),
340
+ isIncomplete: boolCallInfo.isIncomplete,
341
+ };
342
+ };
472
343
  }
473
344
  // Look for a TypeGuard function.
474
345
  const isFunctionReturnTypeGuard = (type) => {
@@ -645,11 +516,9 @@ function getTypeNarrowingCallback(evaluator, reference, testExpression, isPositi
645
516
  // We normally won't find a "not" operator here because they are stripped out
646
517
  // by the binder when it creates condition flow nodes, but we can find this
647
518
  // in the case of local variables type narrowing.
648
- if (reference.nodeType === 38 /* ParseNodeType.Name */) {
649
- if (testExpression.nodeType === 55 /* ParseNodeType.UnaryOperation */ &&
650
- testExpression.d.operator === 38 /* OperatorType.Not */) {
651
- return getTypeNarrowingCallback(evaluator, reference, testExpression.d.expr, !isPositiveTest, nodeInfo, recursionCount);
652
- }
519
+ const notExpressionInfo = TypeEvaluatorNarrowing.getNotExpressionNarrowingInfo(reference, testExpression, isPositiveTest);
520
+ if (reference.nodeType === 38 /* ParseNodeType.Name */ && notExpressionInfo) {
521
+ return getTypeNarrowingCallback(evaluator, reference, notExpressionInfo.innerExpression, notExpressionInfo.adjIsPositiveTest, nodeInfo, recursionCount);
653
522
  }
654
523
  return undefined;
655
524
  }
@@ -744,377 +613,34 @@ function getTypeNarrowingCallbackForAssignmentExpression(evaluator, reference, t
744
613
  getTypeNarrowingCallback(evaluator, reference, testExpression.d.name, isPositiveTest, nodeInfo, recursionCount));
745
614
  }
746
615
  function narrowTypeForUserDefinedTypeGuard(evaluator, type, typeGuardType, isPositiveTest, isStrictTypeGuard, errorNode, nodeInfo) {
747
- // For non-strict type guards, always narrow to the typeGuardType
748
- // in the positive case and don't narrow in the negative case.
749
- if (!isStrictTypeGuard) {
750
- let result = type;
751
- if (isPositiveTest) {
752
- result = typeGuardType;
753
- // If the type guard is a non-constrained TypeVar, add a
754
- // condition to the resulting type.
755
- if ((0, types_1.isTypeVar)(type) && !(0, types_1.isParamSpec)(type) && !types_1.TypeVarType.hasConstraints(type)) {
756
- result = (0, typeUtils_1.addConditionToType)(result, [{ typeVar: type, constraintIndex: 0 }]);
757
- }
758
- return result;
759
- }
760
- return result;
761
- }
762
- const filterTypes = [];
763
- (0, typeUtils_1.doForEachSubtype)(typeGuardType, (typeGuardSubtype) => {
764
- filterTypes.push((0, typeUtils_1.convertToInstantiable)(typeGuardSubtype));
765
- });
766
- return narrowTypeForInstanceOrSubclass(evaluator, type, filterTypes,
767
- /* isInstanceCheck */ true,
768
- /* isTypeIsCheck */ true, isPositiveTest, errorNode, nodeInfo);
616
+ return TypeEvaluatorNarrowing.narrowTypeForUserDefinedTypeGuard(evaluator, type, typeGuardType, isPositiveTest, isStrictTypeGuard, errorNode, nodeInfo, narrowTypeForInstanceOrSubclass);
769
617
  }
770
618
  // Narrow the type based on whether the subtype can be true or false.
771
619
  function narrowTypeForTruthiness(evaluator, type, isPositiveTest) {
772
- return (0, typeUtils_1.mapSubtypes)(type, (subtype) => {
773
- if (isPositiveTest) {
774
- if (evaluator.canBeTruthy(subtype)) {
775
- return evaluator.removeFalsinessFromType(subtype);
776
- }
777
- }
778
- else {
779
- if (evaluator.canBeFalsy(subtype)) {
780
- return evaluator.removeTruthinessFromType(subtype);
781
- }
782
- }
783
- return undefined;
784
- });
620
+ return TypeEvaluatorNarrowing.narrowTypeForTruthiness(evaluator, type, isPositiveTest);
785
621
  }
786
622
  // Handle type narrowing for expressions of the form "a[I] is None" and "a[I] is not None" where
787
623
  // I is an integer and a is a union of Tuples (or subtypes thereof) with known lengths and entry types.
788
624
  function narrowTupleTypeForIsNone(evaluator, type, isPositiveTest, indexValue) {
789
- return evaluator.mapSubtypesExpandTypeVars(type, /* options */ undefined, (subtype) => {
790
- const tupleType = (0, typeUtils_1.getSpecializedTupleType)(subtype);
791
- if (!tupleType || (0, typeUtils_1.isUnboundedTupleClass)(tupleType) || !tupleType.priv.tupleTypeArgs) {
792
- return subtype;
793
- }
794
- const tupleLength = tupleType.priv.tupleTypeArgs.length;
795
- if (indexValue < 0 || indexValue >= tupleLength) {
796
- return subtype;
797
- }
798
- const typeOfEntry = evaluator.makeTopLevelTypeVarsConcrete(tupleType.priv.tupleTypeArgs[indexValue].type);
799
- if (isPositiveTest) {
800
- if (!evaluator.assignType(typeOfEntry, evaluator.getNoneType())) {
801
- return undefined;
802
- }
803
- }
804
- else {
805
- if ((0, typeUtils_1.isNoneInstance)(typeOfEntry)) {
806
- return undefined;
807
- }
808
- }
809
- return subtype;
810
- });
811
- }
812
- // Walks a chain of NewType instances down to the innermost non-NewType base
813
- // instance (e.g. NewType("Y", NewType("X", bool)) -> an instance of bool).
814
- // Returns undefined if `subtype` is not a NewType instance or its base cannot
815
- // be resolved to a class.
816
- function getInnermostNewTypeBaseInstance(subtype) {
817
- if (!(0, types_1.isClassInstance)(subtype) || !types_1.ClassType.isNewTypeClass(subtype)) {
818
- return undefined;
819
- }
820
- let currentType = subtype;
821
- while ((0, types_1.isClassInstance)(currentType) && types_1.ClassType.isNewTypeClass(currentType)) {
822
- if (currentType.shared.baseClasses.length === 0) {
823
- return undefined;
824
- }
825
- const baseClass = currentType.shared.baseClasses[0];
826
- if (!(0, types_1.isClass)(baseClass)) {
827
- return undefined;
828
- }
829
- currentType = types_1.ClassType.cloneAsInstance(baseClass);
830
- }
831
- return currentType;
625
+ return TypeEvaluatorNarrowing.narrowTupleTypeForIsNone(evaluator, type, isPositiveTest, indexValue);
832
626
  }
833
627
  // Handle type narrowing for expressions of the form "x is None" and "x is not None".
834
628
  function narrowTypeForIsNone(evaluator, type, isPositiveTest) {
835
- const expandedType = (0, typeUtils_1.mapSubtypes)(type, (subtype) => {
836
- return (0, typeUtils_1.transformPossibleRecursiveTypeAlias)(subtype);
837
- });
838
- let resultIncludesNoneSubtype = false;
839
- const result = evaluator.mapSubtypesExpandTypeVars(expandedType,
840
- /* options */ undefined, (subtype, unexpandedSubtype) => {
841
- if ((0, types_1.isAnyOrUnknown)(subtype)) {
842
- // Narrow to None in positive tests, matching the behavior of other
843
- // narrowing functions (narrowTypeForInstanceOrSubclass, narrowTypeForLiteralComparison).
844
- if (isPositiveTest) {
845
- resultIncludesNoneSubtype = true;
846
- return (0, typeUtils_1.addConditionToType)(evaluator.getNoneType(), subtype.props?.condition);
847
- }
848
- // For negative tests, keep the original type.
849
- return subtype;
850
- }
851
- let useExpandedSubtype = false;
852
- if ((0, types_1.isTypeVar)(unexpandedSubtype) && !types_1.TypeVarType.isSelf(unexpandedSubtype)) {
853
- // If the TypeVar has value constraints and one or more of them
854
- // are possibly compatible with None, use the expanded subtypes.
855
- if (unexpandedSubtype.shared.constraints.some((constraint) => {
856
- return evaluator.assignType(constraint, evaluator.getNoneType());
857
- })) {
858
- useExpandedSubtype = true;
859
- }
860
- // If the TypeVar han an explicit bound that is possibly compatible
861
- // with None (e.g. "T: int | None"), use the expanded subtypes.
862
- if (unexpandedSubtype.shared.boundType &&
863
- evaluator.assignType(unexpandedSubtype.shared.boundType, evaluator.getNoneType())) {
864
- useExpandedSubtype = true;
865
- }
866
- }
867
- const adjustedSubtype = useExpandedSubtype ? subtype : unexpandedSubtype;
868
- // A NewType whose innermost base is exactly None (e.g. NewType("Apple", NoneType))
869
- // can be identity-compared with None: keep the NewType identity on the positive
870
- // branch and eliminate it on the negative branch. A NewType whose base is merely
871
- // None-compatible (e.g. NewType("Obj", object)) is intentionally not handled here;
872
- // it falls through to the generic checks below so that "is not None" does not
873
- // incorrectly collapse to Never.
874
- const newTypeBaseInstance = getInnermostNewTypeBaseInstance(adjustedSubtype);
875
- if (newTypeBaseInstance && (0, typeUtils_1.isNoneInstance)(newTypeBaseInstance)) {
876
- resultIncludesNoneSubtype = true;
877
- return isPositiveTest ? adjustedSubtype : undefined;
878
- }
879
- // Is it an exact match for None?
880
- if ((0, typeUtils_1.isNoneInstance)(subtype)) {
881
- resultIncludesNoneSubtype = true;
882
- return isPositiveTest ? adjustedSubtype : undefined;
883
- }
884
- // Is it potentially None?
885
- if (evaluator.assignType(subtype, evaluator.getNoneType())) {
886
- resultIncludesNoneSubtype = true;
887
- return isPositiveTest
888
- ? (0, typeUtils_1.addConditionToType)(evaluator.getNoneType(), subtype.props?.condition)
889
- : adjustedSubtype;
890
- }
891
- return isPositiveTest ? undefined : adjustedSubtype;
892
- });
893
- // If this is a positive test and the result is a union that includes None,
894
- // we can eliminate all the non-None subtypes include Any or Unknown. If some
895
- // of the subtypes are None types with conditions, retain those.
896
- if (isPositiveTest && resultIncludesNoneSubtype) {
897
- return (0, typeUtils_1.mapSubtypes)(result, (subtype) => {
898
- const baseInstance = getInnermostNewTypeBaseInstance(subtype);
899
- return (0, typeUtils_1.isNoneInstance)(subtype) || (baseInstance && (0, typeUtils_1.isNoneInstance)(baseInstance)) ? subtype : undefined;
900
- });
901
- }
902
- return result;
629
+ return TypeEvaluatorNarrowing.narrowTypeForIsNone(evaluator, type, isPositiveTest);
903
630
  }
904
631
  // Handle type narrowing for expressions of the form "x is ..." and "x is not ...".
905
632
  function narrowTypeForIsEllipsis(evaluator, node, type, isPositiveTest) {
906
- const expandedType = (0, typeUtils_1.mapSubtypes)(type, (subtype) => {
907
- return (0, typeUtils_1.transformPossibleRecursiveTypeAlias)(subtype);
908
- });
909
- let resultIncludesEllipsisSubtype = false;
910
- const ellipsisType = evaluator.getBuiltInObject(node, 'EllipsisType') ??
911
- evaluator.getBuiltInObject(node, 'ellipsis') ??
912
- types_1.AnyType.create();
913
- const isEllipsisInstance = (subtype) => {
914
- return (0, types_1.isClassInstance)(subtype) && types_1.ClassType.isBuiltIn(subtype, ['EllipsisType', 'ellipsis']);
915
- };
916
- const result = evaluator.mapSubtypesExpandTypeVars(expandedType,
917
- /* options */ undefined, (subtype, unexpandedSubtype) => {
918
- if ((0, types_1.isAnyOrUnknown)(subtype)) {
919
- // We need to assume that "Any" is always both ellipsis and not ellipsis,
920
- // so it matches regardless of whether the test is positive or negative.
921
- return subtype;
922
- }
923
- // If this is a TypeVar that isn't constrained, use the unexpanded
924
- // TypeVar. For all other cases (including constrained TypeVars),
925
- // use the expanded subtype.
926
- const adjustedSubtype = (0, types_1.isTypeVar)(unexpandedSubtype) && !types_1.TypeVarType.hasConstraints(unexpandedSubtype)
927
- ? unexpandedSubtype
928
- : subtype;
929
- // Only a NewType whose innermost base is exactly the ellipsis type is treated
930
- // as the singleton (see narrowTypeForIsNone for the rationale); a merely
931
- // ellipsis-compatible base falls through so "is not ..." does not collapse to Never.
932
- const newTypeBaseInstance = getInnermostNewTypeBaseInstance(adjustedSubtype);
933
- if (newTypeBaseInstance && isEllipsisInstance(newTypeBaseInstance)) {
934
- resultIncludesEllipsisSubtype = true;
935
- return isPositiveTest ? adjustedSubtype : undefined;
936
- }
937
- // Is it an exact match for ellipsis?
938
- if (isEllipsisInstance(subtype)) {
939
- resultIncludesEllipsisSubtype = true;
940
- return isPositiveTest ? adjustedSubtype : undefined;
941
- }
942
- // Is it potentially ellipsis?
943
- if (evaluator.assignType(subtype, ellipsisType)) {
944
- resultIncludesEllipsisSubtype = true;
945
- return isPositiveTest ? (0, typeUtils_1.addConditionToType)(ellipsisType, subtype.props?.condition) : adjustedSubtype;
946
- }
947
- return isPositiveTest ? undefined : adjustedSubtype;
948
- });
949
- // If this is a positive test and the result is a union that includes ellipsis,
950
- // we can eliminate all the non-ellipsis subtypes include Any or Unknown. If some
951
- // of the subtypes are ellipsis types with conditions, retain those.
952
- if (isPositiveTest && resultIncludesEllipsisSubtype) {
953
- return (0, typeUtils_1.mapSubtypes)(result, (subtype) => {
954
- const baseInstance = getInnermostNewTypeBaseInstance(subtype);
955
- return isEllipsisInstance(subtype) || (baseInstance && isEllipsisInstance(baseInstance))
956
- ? subtype
957
- : undefined;
958
- });
959
- }
960
- return result;
633
+ return TypeEvaluatorNarrowing.narrowTypeForIsEllipsis(evaluator, node, type, isPositiveTest);
961
634
  }
962
635
  // The "isinstance" and "issubclass" calls accept classes, runtime unions,
963
636
  // and arbitrarily-nested tuples of these. This method extracts possible
964
637
  // classes and guaranteed negative filters,
965
638
  // or undefined if the filter contains a non-class type.
966
639
  function getIsInstanceClassTypes(evaluator, argType, argExpr) {
967
- let foundNonClassType = false;
968
- const classTypes = [];
969
- const negativeClassTypes = [];
970
- // Create a helper function that returns a list of class types or
971
- // undefined if any of the types are not valid.
972
- const addClassTypesToList = (types, isAmbiguous, isUnboundedEntry) => {
973
- types.forEach((subtype) => {
974
- if ((0, types_1.isClass)(subtype)) {
975
- subtype = (0, typeUtils_1.specializeWithUnknownTypeArgs)(subtype, evaluator.getTupleClassType());
976
- if ((0, types_1.isInstantiableClass)(subtype) && types_1.ClassType.isBuiltIn(subtype, 'Callable')) {
977
- subtype = (0, typeUtils_1.convertToInstantiable)((0, typeUtils_1.getUnknownTypeForCallable)());
978
- }
979
- else if (types_1.TypeBase.isInstance(subtype) && types_1.ClassType.isBuiltIn(subtype, 'type')) {
980
- if (subtype.priv.typeArgs && subtype.priv.typeArgs.length > 0) {
981
- const typeArg = subtype.priv.typeArgs[0];
982
- if ((0, types_1.isAnyOrUnknown)(typeArg)) {
983
- foundNonClassType = true;
984
- return;
985
- }
986
- if ((0, types_1.isInstantiableClass)(typeArg)) {
987
- subtype = types_1.ClassType.cloneIncludeSubclasses(typeArg);
988
- }
989
- else if ((0, types_1.isClassInstance)(typeArg)) {
990
- subtype = types_1.ClassType.cloneAsInstantiable(typeArg);
991
- }
992
- }
993
- }
994
- }
995
- let classType;
996
- if ((0, types_1.isInstantiableClass)(subtype)) {
997
- // If this is a reference to a class that has type promotions (e.g.
998
- // float or complex), remove the promotions for purposes of the
999
- // isinstance check).
1000
- if (!subtype.priv.includeSubclasses && subtype.priv.includePromotions) {
1001
- subtype = types_1.ClassType.cloneRemoveTypePromotions(subtype);
1002
- }
1003
- classType = subtype;
1004
- }
1005
- else if ((0, types_1.isTypeVar)(subtype) && types_1.TypeBase.isInstantiable(subtype)) {
1006
- classType = subtype;
1007
- }
1008
- else if ((0, typeUtils_1.isNoneTypeClass)(subtype)) {
1009
- (0, debug_1.assert)((0, types_1.isInstantiableClass)(subtype));
1010
- classType = subtype;
1011
- }
1012
- else if ((0, types_1.isFunction)(subtype) &&
1013
- subtype.shared.parameters.length === 2 &&
1014
- subtype.shared.parameters[0].category === 1 /* ParamCategory.ArgsList */ &&
1015
- subtype.shared.parameters[1].category === 2 /* ParamCategory.KwargsDict */) {
1016
- classType = subtype;
1017
- }
1018
- else {
1019
- foundNonClassType = true;
1020
- return;
1021
- }
1022
- classTypes.push(classType);
1023
- // Unbounded entries may be absent, and alternative class objects
1024
- // are not all guaranteed to participate in the runtime check.
1025
- if (!isUnboundedEntry && !isAmbiguous) {
1026
- negativeClassTypes.push(classType);
1027
- }
1028
- });
1029
- };
1030
- const addClassTypesRecursive = (type, isAmbiguous, isUnboundedEntry, recursionCount, expression) => {
1031
- if (recursionCount > types_1.maxTypeRecursionCount) {
1032
- return;
1033
- }
1034
- // A runtime union checks both operands, but either operand can itself
1035
- // be an alternative class object. Keep their certainty separate.
1036
- if ((0, types_1.isUnion)(type) &&
1037
- expression?.nodeType === 7 /* ParseNodeType.BinaryOperation */ &&
1038
- expression.d.operator === 6 /* OperatorType.BitwiseOr */) {
1039
- const leftType = evaluator.getCachedType(expression.d.leftExpr);
1040
- const rightType = evaluator.getCachedType(expression.d.rightExpr);
1041
- if (leftType &&
1042
- rightType &&
1043
- !(0, operations_1.customMetaclassSupportsMethod)(leftType, '__or__') &&
1044
- !(0, operations_1.customMetaclassSupportsMethod)(rightType, '__ror__')) {
1045
- // Match the union evaluator's normalization of None operands to NoneType.
1046
- const adjustedLeftType = (0, typeUtils_1.isNoneInstance)(leftType)
1047
- ? (0, typeUtils_1.convertToInstantiable)(evaluator.getNoneType())
1048
- : leftType;
1049
- const adjustedRightType = (0, typeUtils_1.isNoneInstance)(rightType)
1050
- ? (0, typeUtils_1.convertToInstantiable)(evaluator.getNoneType())
1051
- : rightType;
1052
- addClassTypesRecursive(adjustedLeftType, isAmbiguous, isUnboundedEntry, recursionCount, expression.d.leftExpr);
1053
- addClassTypesRecursive(adjustedRightType, isAmbiguous, isUnboundedEntry, recursionCount, expression.d.rightExpr);
1054
- return;
1055
- }
1056
- }
1057
- const isRuntimeUnion = type.props?.specialForm && types_1.ClassType.isBuiltIn(type.props.specialForm, 'UnionType');
1058
- const isAmbiguousType = isAmbiguous || ((0, types_1.isUnion)(type) && !isRuntimeUnion);
1059
- (0, typeUtils_1.doForEachSubtype)(type, (subtype) => {
1060
- if ((0, types_1.isClassInstance)(subtype) && (0, typeUtils_1.isTupleClass)(subtype)) {
1061
- if (subtype.priv.tupleTypeArgs) {
1062
- let entryExpressions;
1063
- if (expression?.nodeType === 52 /* ParseNodeType.Tuple */) {
1064
- const expressions = [];
1065
- expression.d.items.forEach((item) => {
1066
- if (item.nodeType !== 56 /* ParseNodeType.Unpack */) {
1067
- expressions.push(item);
1068
- return;
1069
- }
1070
- const unpackedType = evaluator.getCachedType(item.d.expr);
1071
- const entryCount = unpackedType && (0, types_1.isClassInstance)(unpackedType) && (0, typeUtils_1.isTupleClass)(unpackedType)
1072
- ? unpackedType.priv.tupleTypeArgs?.length ?? 1
1073
- : 1;
1074
- for (let index = 0; index < entryCount; index++) {
1075
- expressions.push(undefined);
1076
- }
1077
- });
1078
- if (expressions.length === subtype.priv.tupleTypeArgs.length) {
1079
- entryExpressions = expressions;
1080
- }
1081
- }
1082
- subtype.priv.tupleTypeArgs.forEach((tupleEntry, index) => {
1083
- addClassTypesRecursive(tupleEntry.type, isAmbiguousType, isUnboundedEntry || tupleEntry.isUnbounded, recursionCount + 1, entryExpressions?.[index]);
1084
- });
1085
- }
1086
- }
1087
- else {
1088
- addClassTypesToList([subtype], isAmbiguousType, isUnboundedEntry);
1089
- }
1090
- });
1091
- };
1092
- addClassTypesRecursive(argType, /* isAmbiguous */ false, /* isUnboundedEntry */ false, 0, argExpr);
1093
- return foundNonClassType ? undefined : { classTypes, negativeClassTypes };
640
+ return TypeEvaluatorNarrowing.getIsInstanceClassTypes(evaluator, argType, argExpr);
1094
641
  }
1095
642
  function narrowTypeForInstanceOrSubclass(evaluator, type, filterTypes, isInstanceCheck, isTypeIsCheck, isPositiveTest, errorNode, nodeInfo) {
1096
- if (!isInstanceCheck && !isTypeIsCheck && !isPositiveTest) {
1097
- // A custom subclass check can reject even the exact same final class.
1098
- // Preserve the existing narrowing policy for non-final classes, including ABCs.
1099
- filterTypes = filterTypes.filter((filterType) => {
1100
- const concreteFilterType = evaluator.makeTopLevelTypeVarsConcrete(filterType);
1101
- return (!(0, types_1.isInstantiableClass)(concreteFilterType) ||
1102
- !types_1.ClassType.isFinal(concreteFilterType) ||
1103
- !(0, operations_1.customMetaclassSupportsMethod)(concreteFilterType, '__subclasscheck__'));
1104
- });
1105
- }
1106
- if (!isPositiveTest && filterTypes.length === 0) {
1107
- return type;
1108
- }
1109
- // First try with intersection types disallowed.
1110
- const narrowedType = narrowTypeForInstanceOrSubclassInternal(evaluator, type, filterTypes, isInstanceCheck, isTypeIsCheck, isPositiveTest,
1111
- /* allowIntersections */ false, errorNode, nodeInfo);
1112
- if (!(0, types_1.isNever)(narrowedType)) {
1113
- return narrowedType;
1114
- }
1115
- // Try again with intersection types allowed.
1116
- return narrowTypeForInstanceOrSubclassInternal(evaluator, type, filterTypes, isInstanceCheck, isTypeIsCheck, isPositiveTest,
1117
- /* allowIntersections */ true, errorNode, nodeInfo);
643
+ return TypeEvaluatorNarrowing.narrowTypeForInstanceOrSubclass(evaluator, type, filterTypes, isInstanceCheck, isTypeIsCheck, isPositiveTest, errorNode, nodeInfo, narrowTypeForInstanceOrSubclassInternal);
1118
644
  }
1119
645
  function narrowTypeForInstanceOrSubclassInternal(evaluator, type, filterTypes, isInstanceCheck, isTypeIsCheck, isPositiveTest, allowIntersections, errorNode, nodeInfo) {
1120
646
  const result = (0, typeUtils_1.mapSubtypes)(type, (subtype) => {
@@ -1594,756 +1120,91 @@ function intersectTupleTypes(type1, type2) {
1594
1120
  }
1595
1121
  // Attempts to narrow a union of tuples based on their known length.
1596
1122
  function narrowTypeForTupleLength(evaluator, referenceType, lengthValue, isPositiveTest, isLessThanCheck) {
1597
- return (0, typeUtils_1.mapSubtypes)(referenceType, (subtype) => {
1598
- const concreteSubtype = evaluator.makeTopLevelTypeVarsConcrete(subtype);
1599
- // If it's not a tuple, we can't narrow it.
1600
- if (!(0, types_1.isClassInstance)(concreteSubtype) ||
1601
- !(0, typeUtils_1.isTupleClass)(concreteSubtype) ||
1602
- !concreteSubtype.priv.tupleTypeArgs) {
1603
- return subtype;
1604
- }
1605
- // If the tuple contains a TypeVarTuple, we can't narrow it.
1606
- if (concreteSubtype.priv.tupleTypeArgs.some((typeArg) => (0, types_1.isUnpackedTypeVarTuple)(typeArg.type))) {
1607
- return subtype;
1608
- }
1609
- // If the tuple contains no unbounded elements, then we know its length exactly.
1610
- if (!concreteSubtype.priv.tupleTypeArgs.some((typeArg) => typeArg.isUnbounded)) {
1611
- const tupleLengthMatches = isLessThanCheck
1612
- ? concreteSubtype.priv.tupleTypeArgs.length < lengthValue
1613
- : concreteSubtype.priv.tupleTypeArgs.length === lengthValue;
1614
- return tupleLengthMatches === isPositiveTest ? subtype : undefined;
1615
- }
1616
- // The tuple contains a "...". We'll expand this into as many elements as
1617
- // necessary to match the lengthValue.
1618
- const elementsToAdd = lengthValue - concreteSubtype.priv.tupleTypeArgs.length + 1;
1619
- if (!isLessThanCheck) {
1620
- // If the specified length is smaller than the minimum length of this tuple,
1621
- // we can rule it out for a positive test and rule it in for a negative test.
1622
- if (elementsToAdd < 0) {
1623
- return isPositiveTest ? undefined : subtype;
1624
- }
1625
- if (!isPositiveTest) {
1626
- // If this is an equality check for the minimum length (e.g.
1627
- // "len(x) == 0"), we can expand the minimum length by one).
1628
- const minLen = concreteSubtype.priv.tupleTypeArgs.length - 1;
1629
- if (lengthValue === minLen) {
1630
- return expandUnboundedTupleElement(concreteSubtype, 1, /* keepUnbounded */ true);
1631
- }
1632
- return subtype;
1633
- }
1634
- return expandUnboundedTupleElement(concreteSubtype, elementsToAdd, /* keepUnbounded */ false);
1635
- }
1636
- // If this is a tuple related to an "*args: P.args" parameter, don't expand it.
1637
- if ((0, types_1.isParamSpec)(subtype) && subtype.priv.paramSpecAccess) {
1638
- return subtype;
1639
- }
1640
- // Place an upper limit on the number of union subtypes we
1641
- // will expand the tuple to.
1642
- const maxTupleUnionExpansion = 32;
1643
- if (elementsToAdd > maxTupleUnionExpansion) {
1644
- return subtype;
1645
- }
1646
- if (isPositiveTest) {
1647
- if (elementsToAdd < 1) {
1648
- return undefined;
1649
- }
1650
- const typesToCombine = [];
1651
- for (let i = 0; i < elementsToAdd; i++) {
1652
- typesToCombine.push(expandUnboundedTupleElement(concreteSubtype, i, /* keepUnbounded */ false));
1653
- }
1654
- return (0, types_1.combineTypes)(typesToCombine);
1655
- }
1656
- return expandUnboundedTupleElement(concreteSubtype, elementsToAdd, /* keepUnbounded */ true);
1657
- });
1123
+ return TypeEvaluatorNarrowing.narrowTypeForTupleLength(evaluator, referenceType, lengthValue, isPositiveTest, isLessThanCheck);
1658
1124
  }
1659
1125
  // Expands a tuple type that contains an unbounded element to include
1660
1126
  // multiple bounded elements of that same type in place of (or in addition
1661
1127
  // to) the unbounded element.
1662
- function expandUnboundedTupleElement(tupleType, elementsToAdd, keepUnbounded) {
1663
- const tupleTypeArgs = [];
1664
- tupleType.priv.tupleTypeArgs.forEach((typeArg) => {
1665
- if (!typeArg.isUnbounded) {
1666
- tupleTypeArgs.push(typeArg);
1667
- }
1668
- else {
1669
- for (let i = 0; i < elementsToAdd; i++) {
1670
- tupleTypeArgs.push({ isUnbounded: false, type: typeArg.type });
1671
- }
1672
- if (keepUnbounded) {
1673
- tupleTypeArgs.push(typeArg);
1674
- }
1675
- }
1676
- });
1677
- return (0, typeUtils_1.specializeTupleClass)(tupleType, tupleTypeArgs);
1678
- }
1679
1128
  // Attempts to narrow a type (make it more constrained) based on an "in" binary operator.
1680
1129
  function narrowTypeForContainerType(evaluator, referenceType, containerType, isPositiveTest) {
1681
- if (isPositiveTest) {
1682
- const elementType = getElementTypeForContainerNarrowing(containerType);
1683
- if (!elementType) {
1684
- return referenceType;
1685
- }
1686
- return narrowTypeForContainerElementType(evaluator, referenceType, evaluator.makeTopLevelTypeVarsConcrete(elementType));
1687
- }
1688
- // Narrowing in the negative case is possible only with tuples
1689
- // with a known length.
1690
- if (!(0, types_1.isClassInstance)(containerType) ||
1691
- !types_1.ClassType.isBuiltIn(containerType, 'tuple') ||
1692
- !containerType.priv.tupleTypeArgs) {
1693
- return referenceType;
1694
- }
1695
- // Determine which tuple types can be eliminated. Only "None" and
1696
- // literal types can be handled here.
1697
- const typesToEliminate = [];
1698
- containerType.priv.tupleTypeArgs.forEach((tupleEntry) => {
1699
- if (!tupleEntry.isUnbounded) {
1700
- if ((0, typeUtils_1.isNoneInstance)(tupleEntry.type)) {
1701
- typesToEliminate.push(tupleEntry.type);
1702
- }
1703
- else if ((0, types_1.isClassInstance)(tupleEntry.type) && (0, typeUtils_1.isLiteralType)(tupleEntry.type)) {
1704
- typesToEliminate.push(tupleEntry.type);
1705
- }
1706
- }
1707
- });
1708
- if (typesToEliminate.length === 0) {
1709
- return referenceType;
1710
- }
1711
- return (0, typeUtils_1.mapSubtypes)(referenceType, (referenceSubtype) => {
1712
- referenceSubtype = evaluator.makeTopLevelTypeVarsConcrete(referenceSubtype);
1713
- if ((0, types_1.isClassInstance)(referenceSubtype) && referenceSubtype.priv.literalValue === undefined) {
1714
- // If we're able to enumerate all possible literal values
1715
- // (for bool or enum), we can eliminate all others in a negative test.
1716
- const allLiteralTypes = enumerateLiteralsForType(evaluator, referenceSubtype);
1717
- if (allLiteralTypes && allLiteralTypes.length > 0) {
1718
- return (0, types_1.combineTypes)(allLiteralTypes.filter((type) => !typesToEliminate.some((t) => (0, types_1.isTypeSame)(t, type))));
1719
- }
1720
- }
1721
- if (typesToEliminate.some((t) => (0, types_1.isTypeSame)(t, referenceSubtype))) {
1722
- return undefined;
1723
- }
1724
- return referenceSubtype;
1725
- });
1130
+ return TypeEvaluatorNarrowing.narrowTypeForContainerType(evaluator, referenceType, containerType, isPositiveTest);
1726
1131
  }
1727
1132
  function getElementTypeForContainerNarrowing(containerType) {
1728
- // We support contains narrowing only for certain built-in types that have been specialized.
1729
- const supportedContainers = ['list', 'set', 'frozenset', 'deque', 'tuple', 'dict', 'defaultdict', 'OrderedDict'];
1730
- if (!(0, types_1.isClassInstance)(containerType) || !types_1.ClassType.isBuiltIn(containerType, supportedContainers)) {
1731
- return undefined;
1732
- }
1733
- if (!containerType.priv.typeArgs || containerType.priv.typeArgs.length < 1) {
1734
- return undefined;
1735
- }
1736
- let elementType = containerType.priv.typeArgs[0];
1737
- if ((0, typeUtils_1.isTupleClass)(containerType) && containerType.priv.tupleTypeArgs) {
1738
- elementType = (0, types_1.combineTypes)(containerType.priv.tupleTypeArgs.map((t) => t.type));
1739
- }
1740
- return elementType;
1133
+ return TypeEvaluatorNarrowing.getElementTypeForContainerNarrowing(containerType);
1741
1134
  }
1742
1135
  function narrowTypeForContainerElementType(evaluator, referenceType, elementType) {
1743
- return evaluator.mapSubtypesExpandTypeVars(referenceType, /* options */ undefined, (referenceSubtype) => {
1744
- return (0, typeUtils_1.mapSubtypes)(elementType, (elementSubtype) => {
1745
- if ((0, types_1.isAnyOrUnknown)(elementSubtype)) {
1746
- return referenceSubtype;
1747
- }
1748
- // If the two types are disjoint (i.e. are not comparable), eliminate this subtype.
1749
- if (!evaluator.isTypeComparable(elementSubtype, referenceSubtype)) {
1750
- return undefined;
1751
- }
1752
- // If one of the two types is a literal, we can narrow to that type.
1753
- if ((0, types_1.isClassInstance)(elementSubtype) &&
1754
- ((0, typeUtils_1.isLiteralLikeType)(elementSubtype) || (0, typeUtils_1.isNoneInstance)(elementSubtype)) &&
1755
- evaluator.assignType(referenceSubtype, elementSubtype)) {
1756
- return (0, typeUtils_1.stripTypeForm)((0, typeUtils_1.addConditionToType)(elementSubtype, referenceSubtype.props?.condition));
1757
- }
1758
- if ((0, types_1.isClassInstance)(referenceSubtype) &&
1759
- ((0, typeUtils_1.isLiteralLikeType)(referenceSubtype) || (0, typeUtils_1.isNoneInstance)(referenceSubtype)) &&
1760
- evaluator.assignType(elementSubtype, referenceSubtype)) {
1761
- return (0, typeUtils_1.stripTypeForm)((0, typeUtils_1.addConditionToType)(referenceSubtype, elementSubtype.props?.condition));
1762
- }
1763
- // If the element type is a known class object that is assignable to
1764
- // the reference type, we can narrow to that class object.
1765
- if ((0, types_1.isInstantiableClass)(elementSubtype) &&
1766
- !elementSubtype.priv.includeSubclasses &&
1767
- evaluator.assignType(referenceSubtype, elementSubtype)) {
1768
- return (0, typeUtils_1.stripTypeForm)((0, typeUtils_1.addConditionToType)(elementSubtype, referenceSubtype.props?.condition));
1769
- }
1770
- // It's not safe to narrow.
1771
- return referenceSubtype;
1772
- });
1773
- });
1136
+ return TypeEvaluatorNarrowing.narrowTypeForContainerElementType(evaluator, referenceType, elementType);
1774
1137
  }
1775
1138
  // Attempts to narrow a type based on whether it is a TypedDict with
1776
1139
  // a literal key value.
1777
1140
  function narrowTypeForTypedDictKey(evaluator, referenceType, literalKey, isPositiveTest) {
1778
- const narrowedType = evaluator.mapSubtypesExpandTypeVars(referenceType,
1779
- /* options */ undefined, (subtype, unexpandedSubtype) => {
1780
- if ((0, types_1.isParamSpec)(unexpandedSubtype)) {
1781
- return unexpandedSubtype;
1782
- }
1783
- if ((0, types_1.isClassInstance)(subtype) && types_1.ClassType.isTypedDictClass(subtype)) {
1784
- const entries = (0, typedDicts_1.getTypedDictMembersForClass)(evaluator, subtype, /* allowNarrowed */ true);
1785
- const knownEntry = entries.knownItems.get(literalKey.priv.literalValue);
1786
- const tdEntry = knownEntry ?? entries.extraItems;
1787
- if (isPositiveTest) {
1788
- // The code that is commented out below implements the behavior that is technically
1789
- // correct, but until we PEP 728 is ratified and we have a way to express "extra items"
1790
- // and closed TypedDicts, we'll preserve the older (less correct) behavior to enable
1791
- // narrowing of TypedDicts based on checks for specific keys.
1792
- // TODO - remove this behavior once PEP 728 is accepted and the feature is no
1793
- // longer experimental.
1794
- if (!tdEntry) {
1795
- return undefined;
1796
- }
1797
- // if (!tdEntry) {
1798
- // // If there is no TD entry for this key and no "extra items" defined,
1799
- // // we have to assume that the TypedDict may contain extra items, so
1800
- // // narrowing it isn't possible in this case.
1801
- // return subtype;
1802
- // }
1803
- if ((0, types_1.isNever)(tdEntry.valueType)) {
1804
- // If the entry is typed as Never or the "extra items" is typed as Never,
1805
- // then this key cannot be present in the TypedDict, and we can eliminate it.
1806
- // A closed TypedDict has an "extra items" of Never, so this is what allows
1807
- // a key check to discriminate between closed TypedDicts.
1808
- return undefined;
1809
- }
1810
- // If the entry is currently not required and not marked provided, we can mark
1811
- // it as provided after this guard expression confirms it is.
1812
- if (tdEntry.isRequired || tdEntry.isProvided) {
1813
- return subtype;
1814
- }
1815
- const newNarrowedEntriesMap = new Map(subtype.priv.typedDictNarrowedEntries ?? []);
1816
- // Add the new entry.
1817
- newNarrowedEntriesMap.set(literalKey.priv.literalValue, {
1818
- valueType: tdEntry.valueType,
1819
- isReadOnly: tdEntry.isReadOnly,
1820
- isRequired: false,
1821
- isProvided: true,
1822
- });
1823
- // Clone the TypedDict object with the new entries.
1824
- return types_1.ClassType.cloneAsInstance(types_1.ClassType.cloneForNarrowedTypedDictEntries(types_1.ClassType.cloneAsInstantiable(subtype), newNarrowedEntriesMap));
1825
- }
1826
- else {
1827
- if (!knownEntry) {
1828
- // The key is not one of the known items, so it can be supplied
1829
- // only through an "extra items" entry, which says nothing about
1830
- // whether this particular key is present. Its absence is therefore
1831
- // consistent with the type, and the subtype cannot be eliminated.
1832
- return subtype;
1833
- }
1834
- return knownEntry.isRequired || knownEntry.isProvided ? undefined : subtype;
1835
- }
1836
- }
1837
- return subtype;
1838
- });
1839
- return narrowedType;
1141
+ return TypeEvaluatorNarrowing.narrowTypeForTypedDictKey(evaluator, referenceType, literalKey, isPositiveTest);
1840
1142
  }
1841
1143
  // Attempts to narrow a TypedDict type based on a comparison (equal or not
1842
1144
  // equal) between a discriminating entry type that has a declared literal
1843
1145
  // type to a literal value.
1844
1146
  function narrowTypeForDiscriminatedDictEntryComparison(evaluator, referenceType, indexLiteralType, literalType, isPositiveTest) {
1845
- let canNarrow = true;
1846
- const narrowedType = (0, typeUtils_1.mapSubtypes)(referenceType, (subtype) => {
1847
- if ((0, types_1.isClassInstance)(subtype) && types_1.ClassType.isTypedDictClass(subtype)) {
1848
- const symbolMap = (0, typedDicts_1.getTypedDictMembersForClass)(evaluator, subtype);
1849
- const tdEntry = symbolMap.knownItems.get(indexLiteralType.priv.literalValue);
1850
- if (tdEntry && (0, typeUtils_1.isLiteralTypeOrUnion)(tdEntry.valueType)) {
1851
- if (isPositiveTest) {
1852
- let foundMatch = false;
1853
- (0, typeUtils_1.doForEachSubtype)(literalType, (literalSubtype) => {
1854
- if (evaluator.assignType(tdEntry.valueType, literalSubtype)) {
1855
- foundMatch = true;
1856
- }
1857
- });
1858
- return foundMatch ? subtype : undefined;
1859
- }
1860
- else {
1861
- let foundNonMatch = false;
1862
- (0, typeUtils_1.doForEachSubtype)(literalType, (literalSubtype) => {
1863
- if (!evaluator.assignType(literalSubtype, tdEntry.valueType)) {
1864
- foundNonMatch = true;
1865
- }
1866
- });
1867
- return foundNonMatch ? subtype : undefined;
1868
- }
1869
- }
1870
- }
1871
- canNarrow = false;
1872
- return subtype;
1873
- });
1874
- return canNarrow ? narrowedType : referenceType;
1147
+ return TypeEvaluatorNarrowing.narrowTypeForDiscriminatedDictEntryComparison(evaluator, referenceType, indexLiteralType, literalType, isPositiveTest);
1875
1148
  }
1876
1149
  function narrowTypeForDiscriminatedTupleComparison(evaluator, referenceType, indexLiteralType, literalType, isPositiveTest) {
1877
- let canNarrow = true;
1878
- const narrowedType = (0, typeUtils_1.mapSubtypes)(referenceType, (subtype) => {
1879
- if ((0, types_1.isClassInstance)(subtype) &&
1880
- types_1.ClassType.isTupleClass(subtype) &&
1881
- !(0, typeUtils_1.isUnboundedTupleClass)(subtype) &&
1882
- typeof indexLiteralType.priv.literalValue === 'number' &&
1883
- (0, types_1.isClassInstance)(literalType)) {
1884
- const indexValue = indexLiteralType.priv.literalValue;
1885
- if (subtype.priv.tupleTypeArgs && indexValue >= 0 && indexValue < subtype.priv.tupleTypeArgs.length) {
1886
- const tupleEntryType = subtype.priv.tupleTypeArgs[indexValue]?.type;
1887
- if (tupleEntryType && (0, typeUtils_1.isLiteralTypeOrUnion)(tupleEntryType)) {
1888
- if (isPositiveTest) {
1889
- return evaluator.assignType(tupleEntryType, literalType) ? subtype : undefined;
1890
- }
1891
- else {
1892
- return evaluator.assignType(literalType, tupleEntryType) ? undefined : subtype;
1893
- }
1894
- }
1895
- }
1896
- }
1897
- canNarrow = false;
1898
- return subtype;
1899
- });
1900
- return canNarrow ? narrowedType : referenceType;
1150
+ return TypeEvaluatorNarrowing.narrowTypeForDiscriminatedTupleComparison(evaluator, referenceType, indexLiteralType, literalType, isPositiveTest);
1901
1151
  }
1902
1152
  // Attempts to narrow a type based on a comparison (equal or not equal)
1903
1153
  // between a discriminating field that has a declared literal type to a
1904
1154
  // literal value.
1905
1155
  function narrowTypeForDiscriminatedLiteralFieldComparison(evaluator, referenceType, memberName, literalType, isPositiveTest) {
1906
- const narrowedType = (0, typeUtils_1.mapSubtypes)(referenceType, (subtype) => {
1907
- let memberInfo;
1908
- if ((0, types_1.isClassInstance)(subtype)) {
1909
- memberInfo = (0, typeUtils_1.lookUpObjectMember)(subtype, memberName);
1910
- }
1911
- else if ((0, types_1.isInstantiableClass)(subtype)) {
1912
- memberInfo = (0, typeUtils_1.lookUpClassMember)(subtype, memberName);
1913
- }
1914
- if (memberInfo && memberInfo.isTypeDeclared) {
1915
- let memberType = evaluator.getTypeOfMember(memberInfo);
1916
- // Handle the case where the field is a property
1917
- // that has a declared literal return type for its getter.
1918
- if ((0, types_1.isClassInstance)(subtype) && (0, types_1.isClassInstance)(memberType) && (0, typeUtils_1.isProperty)(memberType)) {
1919
- const getterType = memberType.priv.fgetInfo?.methodType;
1920
- if (getterType && (0, types_1.isFunction)(getterType) && getterType.shared.declaredReturnType) {
1921
- const getterReturnType = types_1.FunctionType.getEffectiveReturnType(getterType);
1922
- if (getterReturnType) {
1923
- memberType = getterReturnType;
1924
- }
1925
- }
1926
- }
1927
- if ((0, typeUtils_1.isLiteralTypeOrUnion)(memberType, /* allowNone */ true)) {
1928
- if (isPositiveTest) {
1929
- return evaluator.assignType(memberType, literalType) ? subtype : undefined;
1930
- }
1931
- else {
1932
- return evaluator.assignType(literalType, memberType) ? undefined : subtype;
1933
- }
1934
- }
1935
- }
1936
- return subtype;
1937
- });
1938
- return narrowedType;
1156
+ return TypeEvaluatorNarrowing.narrowTypeForDiscriminatedLiteralFieldComparison(evaluator, referenceType, memberName, literalType, isPositiveTest);
1939
1157
  }
1940
1158
  // Attempts to narrow a type based on a comparison (equal or not equal)
1941
1159
  // between a discriminating field that has a declared None type to a
1942
1160
  // None.
1943
1161
  function narrowTypeForDiscriminatedFieldNoneComparison(evaluator, referenceType, memberName, isPositiveTest) {
1944
- return (0, typeUtils_1.mapSubtypes)(referenceType, (subtype) => {
1945
- let memberInfo;
1946
- if ((0, types_1.isClassInstance)(subtype)) {
1947
- memberInfo = (0, typeUtils_1.lookUpObjectMember)(subtype, memberName);
1948
- }
1949
- else if ((0, types_1.isInstantiableClass)(subtype)) {
1950
- memberInfo = (0, typeUtils_1.lookUpClassMember)(subtype, memberName);
1951
- }
1952
- if (memberInfo && memberInfo.isTypeDeclared) {
1953
- // Check the declared type before narrowing, since the member type
1954
- // below will be concretized and lose descriptor identity.
1955
- const declaredType = evaluator.getDeclaredTypeOfSymbol(memberInfo.symbol)?.type;
1956
- if (!declaredType) {
1957
- // isTypeDeclared is true but the type couldn't be resolved (e.g. an
1958
- // unresolvable stub). Conservatively skip narrowing rather than risk
1959
- // incorrectly eliminating a descriptor-typed member.
1960
- return subtype;
1961
- }
1962
- // Check if any subtype of the declared type is a descriptor or property.
1963
- // isMaybeDescriptorInstance handles declared types in instance form (ClassInstance),
1964
- // while isMaybeDescriptorClass handles declared types in instantiable form
1965
- // (InstantiableClass), which occurs when the annotation refers to the class object itself.
1966
- // This check applies to both positive and negative test paths: descriptor __get__
1967
- // return values don't reflect stored values regardless of test polarity.
1968
- const isDescriptorOrProperty = (0, typeUtils_1.someSubtypes)(declaredType, (declaredSubtype) => (0, typeUtils_1.isProperty)(declaredSubtype) ||
1969
- (0, typeUtils_1.isMaybeDescriptorInstance)(declaredSubtype) ||
1970
- (0, typeUtils_1.isMaybeDescriptorClass)(declaredSubtype));
1971
- if (isDescriptorOrProperty) {
1972
- return subtype;
1973
- }
1974
- const memberType = evaluator.makeTopLevelTypeVarsConcrete(evaluator.getTypeOfMember(memberInfo));
1975
- let canNarrow = true;
1976
- if (isPositiveTest) {
1977
- (0, typeUtils_1.doForEachSubtype)(memberType, (memberSubtype) => {
1978
- memberSubtype = evaluator.makeTopLevelTypeVarsConcrete(memberSubtype);
1979
- if ((0, types_1.isAnyOrUnknown)(memberSubtype) || (0, typeUtils_1.isNoneInstance)(memberSubtype) || (0, types_1.isNever)(memberSubtype)) {
1980
- canNarrow = false;
1981
- }
1982
- });
1983
- }
1984
- else {
1985
- canNarrow = (0, typeUtils_1.isNoneInstance)(memberType);
1986
- }
1987
- if (canNarrow) {
1988
- return undefined;
1989
- }
1990
- }
1991
- return subtype;
1992
- });
1162
+ return TypeEvaluatorNarrowing.narrowTypeForDiscriminatedFieldNoneComparison(evaluator, referenceType, memberName, isPositiveTest);
1993
1163
  }
1164
+ // Determines whether two classes have incompatible disjoint bases (PEP 800),
1165
+ // in which case no class can derive from both of them.
1166
+ // Fill gradual holes without replacing facts inferred from the guarded value.
1994
1167
  // Attempts to narrow a type based on a "type(x) is y" or "type(x) is not y" check.
1995
- function narrowTypeForTypeIs(evaluator, type, classTypes, isPositiveTest) {
1996
- // We currently don't support narrowing in the negative direction
1997
- // when there are more than one class types.
1998
- if (!isPositiveTest && classTypes.length > 1) {
1999
- return type;
2000
- }
2001
- const typesToCombine = classTypes.map((classType) => {
2002
- return evaluator.mapSubtypesExpandTypeVars(type,
2003
- /* options */ undefined, (subtype, unexpandedSubtype) => {
2004
- if ((0, types_1.isClassInstance)(subtype)) {
2005
- const matches = types_1.ClassType.isDerivedFrom(classType, types_1.ClassType.cloneAsInstantiable(subtype));
2006
- if (isPositiveTest) {
2007
- if (matches) {
2008
- if (types_1.ClassType.isSameGenericClass(types_1.ClassType.cloneAsInstantiable(subtype), classType)) {
2009
- return (0, typeUtils_1.addConditionToType)(subtype, (0, typeUtils_1.getTypeCondition)(classType));
2010
- }
2011
- return (0, typeUtils_1.addConditionToType)(types_1.ClassType.cloneAsInstance(classType), subtype.props?.condition);
2012
- }
2013
- if (!classType.priv.includeSubclasses) {
2014
- return undefined;
2015
- }
2016
- if (!(0, types_1.isTypeVar)(unexpandedSubtype) || !types_1.TypeVarType.isSelf(unexpandedSubtype)) {
2017
- return (0, typeUtils_1.addConditionToType)(subtype, classType.props?.condition);
2018
- }
2019
- }
2020
- if (!classType.priv.includeSubclasses) {
2021
- // If the class if marked final and it matches, then
2022
- // we can eliminate it in the negative case.
2023
- if (matches && types_1.ClassType.isFinal(subtype)) {
2024
- return undefined;
2025
- }
2026
- // We can't eliminate the subtype in the negative
2027
- // case because it could be a subclass of the type,
2028
- // in which case `type(x) is y` would fail.
2029
- return subtype;
2030
- }
2031
- }
2032
- if ((0, types_1.isAnyOrUnknown)(subtype)) {
2033
- return isPositiveTest
2034
- ? types_1.ClassType.cloneAsInstance((0, typeUtils_1.addConditionToType)(classType, (0, typeUtils_1.getTypeCondition)(subtype)))
2035
- : subtype;
2036
- }
2037
- return unexpandedSubtype;
2038
- });
2039
- });
2040
- return (0, types_1.combineTypes)(typesToCombine);
2041
- }
2042
- function hasUnresolvedMetaclassInMro(classType) {
2043
- return classType.shared.mro.some((baseClass) => !(0, types_1.isInstantiableClass)(baseClass) || !!(baseClass.shared.flags & 134217728 /* ClassTypeFlags.HasUnresolvedMetaclass */));
1168
+ function narrowTypeForTypeIs(evaluator, type, classTypes, isPositiveTest, isIsOperator, classTypeVar, allowLegacyEquality) {
1169
+ return TypeEvaluatorNarrowing.narrowTypeForTypeIs(evaluator, type, classTypes, isPositiveTest, isIsOperator, classTypeVar, allowLegacyEquality);
2044
1170
  }
2045
1171
  // Determines whether an equality comparison ("==" or "!=") involving the
2046
1172
  // specified class object is guaranteed to have identity semantics. This
2047
1173
  // requires that the class is statically closed (it cannot be a subclass
2048
1174
  // with a different metaclass), is not generic (specialized aliases compare
2049
1175
  // by value), and its metaclass does not override "__eq__" or "__ne__".
2050
- function hasIdentityEqualitySemantics(classType, metaclassEqualityResults) {
2051
- if (classType.priv.includeSubclasses && !types_1.ClassType.isFinal(classType)) {
2052
- return false;
2053
- }
2054
- if (classType.shared.typeParams.length > 0) {
2055
- return false;
2056
- }
2057
- const metaclass = classType.shared.effectiveMetaclass;
2058
- if (!metaclass ||
2059
- !(0, types_1.isInstantiableClass)(metaclass) ||
2060
- hasUnresolvedMetaclassInMro(classType) ||
2061
- hasUnresolvedMetaclassInMro(metaclass)) {
2062
- return false;
2063
- }
2064
- if (types_1.ClassType.isBuiltIn(metaclass, 'type')) {
2065
- return true;
2066
- }
2067
- // Cloned metaclasses share method definitions, but the class-specific checks above cannot be shared.
2068
- const cachedResult = metaclassEqualityResults.get(metaclass.shared);
2069
- if (cachedResult !== undefined) {
2070
- return cachedResult;
2071
- }
2072
- const result = !(0, operations_1.customMetaclassSupportsMethod)(classType, '__eq__') && !(0, operations_1.customMetaclassSupportsMethod)(classType, '__ne__');
2073
- metaclassEqualityResults.set(metaclass.shared, result);
2074
- return result;
2075
- }
1176
+ // Legacy forward type(x) equality guards check declared metaclasses without closing subclass hierarchies.
2076
1177
  // Attempts to narrow a type based on a comparison with a class using "is" or
2077
1178
  // "is not", or "==" or "!=".
2078
1179
  function narrowTypeForClassComparison(evaluator, referenceType, classType, isPositiveTest, isIsOperator = true) {
2079
- // Limit reuse to this invocation so results cannot outlive the evaluation that established them.
2080
- const metaclassEqualityResults = isIsOperator ? undefined : new Map();
2081
- if (metaclassEqualityResults && !hasIdentityEqualitySemantics(classType, metaclassEqualityResults)) {
2082
- return referenceType;
2083
- }
2084
- return (0, typeUtils_1.mapSubtypes)(referenceType, (subtype) => {
2085
- // Multiple class constraints expand to a union with distinct conditions, which equality cannot narrow.
2086
- if (metaclassEqualityResults &&
2087
- (0, types_1.isTypeVar)(subtype) &&
2088
- !subtype.shared.recursiveAlias &&
2089
- subtype.shared.constraints.length > 1 &&
2090
- subtype.shared.constraints.every(types_1.isClassInstance)) {
2091
- return subtype;
2092
- }
2093
- let concreteSubtype = evaluator.makeTopLevelTypeVarsConcrete(subtype);
2094
- if (metaclassEqualityResults &&
2095
- (!(0, types_1.isInstantiableClass)(concreteSubtype) ||
2096
- !hasIdentityEqualitySemantics(concreteSubtype, metaclassEqualityResults))) {
2097
- return subtype;
2098
- }
2099
- if (isPositiveTest) {
2100
- if ((0, types_1.isClassInstance)(concreteSubtype) &&
2101
- types_1.TypeBase.isInstance(subtype) &&
2102
- types_1.ClassType.isBuiltIn(concreteSubtype, 'type')) {
2103
- concreteSubtype =
2104
- concreteSubtype.priv.typeArgs && concreteSubtype.priv.typeArgs.length > 0
2105
- ? (0, typeUtils_1.convertToInstantiable)(concreteSubtype.priv.typeArgs[0])
2106
- : types_1.UnknownType.create();
2107
- }
2108
- if ((0, types_1.isAnyOrUnknown)(concreteSubtype)) {
2109
- return (0, typeUtils_1.addConditionToType)(classType, (0, typeUtils_1.getTypeCondition)(concreteSubtype));
2110
- }
2111
- if ((0, types_1.isClass)(concreteSubtype)) {
2112
- if (types_1.TypeBase.isInstance(concreteSubtype)) {
2113
- if (!isIsOperator) {
2114
- return subtype;
2115
- }
2116
- return types_1.ClassType.isBuiltIn(concreteSubtype, 'object') ? classType : undefined;
2117
- }
2118
- const isSuperType = isFilterSuperclass(subtype, concreteSubtype, classType, classType);
2119
- if (!classType.priv.includeSubclasses) {
2120
- // Handle the case where the LHS and RHS operands are specific
2121
- // classes, as opposed to types that represent classes and their
2122
- // subclasses.
2123
- if (!concreteSubtype.priv.includeSubclasses) {
2124
- return types_1.ClassType.isSameGenericClass(concreteSubtype, classType) ? classType : undefined;
2125
- }
2126
- if (isSuperType) {
2127
- return (0, typeUtils_1.addConditionToType)(classType, (0, typeUtils_1.getTypeCondition)(concreteSubtype));
2128
- }
2129
- const isSubType = types_1.ClassType.isDerivedFrom(classType, concreteSubtype);
2130
- if (isSubType) {
2131
- return (0, typeUtils_1.addConditionToType)(classType, (0, typeUtils_1.getTypeCondition)(concreteSubtype));
2132
- }
2133
- return undefined;
2134
- }
2135
- if (types_1.ClassType.isFinal(concreteSubtype) && !isSuperType) {
2136
- return undefined;
2137
- }
2138
- }
2139
- }
2140
- else {
2141
- if ((0, types_1.isInstantiableClass)(concreteSubtype) &&
2142
- types_1.ClassType.isSameGenericClass(classType, concreteSubtype) &&
2143
- types_1.ClassType.isFinal(classType)) {
2144
- return undefined;
2145
- }
2146
- }
2147
- return subtype;
2148
- });
2149
- }
2150
- function isFilterSuperclass(varType, concreteVarType, filterType, concreteFilterType) {
2151
- if ((0, types_1.isTypeVar)(filterType) || concreteFilterType.priv.literalValue !== undefined) {
2152
- return (0, types_1.isTypeSame)((0, typeUtils_1.convertToInstance)(filterType), varType);
2153
- }
2154
- // If the filter type represents all possible subclasses
2155
- // of a type, we can't make any statements about its superclass
2156
- // relationship with concreteVarType.
2157
- if (concreteFilterType.priv.includeSubclasses) {
2158
- return false;
2159
- }
2160
- if (types_1.ClassType.isDerivedFrom(concreteVarType, concreteFilterType)) {
2161
- return true;
2162
- }
2163
- // Handle the special case where the variable type is a TypedDict and
2164
- // we're filtering against 'dict'. TypedDict isn't derived from dict,
2165
- // but at runtime, isinstance returns True.
2166
- if (types_1.ClassType.isBuiltIn(concreteFilterType, 'dict') && types_1.ClassType.isTypedDictClass(concreteVarType)) {
2167
- return true;
2168
- }
2169
- return false;
1180
+ return TypeEvaluatorNarrowing.narrowTypeForClassComparison(evaluator, referenceType, classType, isPositiveTest, isIsOperator);
2170
1181
  }
2171
1182
  // Determines whether the specified class is an enum class whose members derive
2172
1183
  // from a primitive type (e.g. IntEnum or StrEnum). Members of such classes
2173
1184
  // compare equal to their underlying primitive value at runtime.
2174
- function isPrimitiveBackedEnumClass(classType) {
2175
- if (!types_1.ClassType.isEnumClass(classType)) {
2176
- return false;
2177
- }
2178
- return (0, typeUtils_1.derivesFromStdlibClass)(classType, 'int') || (0, typeUtils_1.derivesFromStdlibClass)(classType, 'str');
2179
- }
2180
1185
  // Determines whether enumType is a primitive-backed enum class and primitiveType
2181
1186
  // is the primitive type (int or str) from which it derives.
2182
- function isPrimitiveBackedEnumAndPrimitive(enumType, primitiveType) {
2183
- if (types_1.ClassType.isEnumClass(primitiveType) || !isPrimitiveBackedEnumClass(enumType)) {
2184
- return false;
2185
- }
2186
- // Exclude bool, which derives from int but whose literal values are distinct
2187
- // from the corresponding int literals.
2188
- if (types_1.ClassType.isBuiltIn(primitiveType, 'int')) {
2189
- return (0, typeUtils_1.derivesFromStdlibClass)(enumType, 'int');
2190
- }
2191
- if (types_1.ClassType.isBuiltIn(primitiveType, 'str')) {
2192
- return (0, typeUtils_1.derivesFromStdlibClass)(enumType, 'str');
2193
- }
2194
- return false;
2195
- }
2196
1187
  // If the specified type is a literal member of a primitive-backed enum class,
2197
1188
  // returns the corresponding primitive literal type. Otherwise returns the type
2198
1189
  // unmodified.
2199
- function unwrapPrimitiveBackedEnumLiteral(classType) {
2200
- const literalValue = classType.priv.literalValue;
2201
- if (!(literalValue instanceof types_1.EnumLiteral) || !isPrimitiveBackedEnumClass(classType)) {
2202
- return classType;
2203
- }
2204
- const itemType = literalValue.itemType;
2205
- if ((0, types_1.isClassInstance)(itemType) && itemType.priv.literalValue !== undefined) {
2206
- return itemType;
2207
- }
2208
- return classType;
2209
- }
2210
1190
  // Determines whether two literal types compare equal using the `==` operator at
2211
1191
  // runtime. This differs from ClassType.isLiteralValueSame only for members of
2212
1192
  // primitive-backed enum classes, which compare equal to their underlying
2213
1193
  // primitive values.
2214
- function isLiteralValueEqualAtRuntime(type1, type2) {
2215
- return types_1.ClassType.isLiteralValueSame(unwrapPrimitiveBackedEnumLiteral(type1), unwrapPrimitiveBackedEnumLiteral(type2));
2216
- }
2217
1194
  // Attempts to narrow a type (make it more constrained) based on a comparison
2218
1195
  // (equal or not equal) to a literal value. It also handles "is" or "is not"
2219
1196
  // operators if isIsOperator is true.
2220
1197
  function narrowTypeForLiteralComparison(evaluator, referenceType, literalType, isPositiveTest, isIsOperator) {
2221
- return evaluator.mapSubtypesExpandTypeVars(referenceType, /* options */ undefined, (subtype) => {
2222
- subtype = evaluator.makeTopLevelTypeVarsConcrete(subtype);
2223
- if ((0, types_1.isAnyOrUnknown)(subtype)) {
2224
- if (isPositiveTest) {
2225
- return literalType;
2226
- }
2227
- return subtype;
2228
- }
2229
- // Determine whether this is a comparison between a primitive-backed enum
2230
- // (e.g. IntEnum or StrEnum) and its underlying primitive type. Such a
2231
- // comparison can be used for narrowing because the enum member compares
2232
- // equal to its underlying primitive value at runtime.
2233
- const isPrimitiveBackedEnumComparison = !isIsOperator &&
2234
- (0, types_1.isClassInstance)(subtype) &&
2235
- (isPrimitiveBackedEnumAndPrimitive(subtype, literalType) ||
2236
- isPrimitiveBackedEnumAndPrimitive(literalType, subtype));
2237
- if ((0, types_1.isClassInstance)(subtype) &&
2238
- (types_1.ClassType.isSameGenericClass(literalType, subtype) || isPrimitiveBackedEnumComparison)) {
2239
- if (subtype.priv.literalValue !== undefined) {
2240
- const literalValueMatches = isPrimitiveBackedEnumComparison
2241
- ? isLiteralValueEqualAtRuntime(subtype, literalType)
2242
- : types_1.ClassType.isLiteralValueSame(subtype, literalType);
2243
- if (isPositiveTest) {
2244
- return literalValueMatches ? subtype : undefined;
2245
- }
2246
- const isSingleton = types_1.ClassType.isEnumClass(literalType) ||
2247
- (0, typeUtils_1.isSentinelLiteral)(subtype) ||
2248
- types_1.ClassType.isBuiltIn(literalType, 'bool');
2249
- // For negative tests, we can eliminate the literal value if it doesn't match,
2250
- // but only for equality tests or for 'is' tests that involve enums, bools, or sentinels.
2251
- return literalValueMatches && (isSingleton || !isIsOperator) ? undefined : subtype;
2252
- }
2253
- if (isPositiveTest) {
2254
- if (isPrimitiveBackedEnumComparison) {
2255
- // If the reference type is the enum, attempt to find the member
2256
- // whose value matches the primitive literal. If no member can be
2257
- // identified (e.g. for an IntFlag class, whose members cannot be
2258
- // enumerated), retain the reference type rather than narrowing it
2259
- // to the primitive literal type.
2260
- if (types_1.ClassType.isEnumClass(subtype)) {
2261
- const allLiteralTypes = enumerateLiteralsForType(evaluator, subtype);
2262
- const match = allLiteralTypes?.find((type) => isLiteralValueEqualAtRuntime(type, literalType));
2263
- return match ?? subtype;
2264
- }
2265
- // The reference type is the primitive type, so narrowing it to the
2266
- // enum literal would lose its (potentially derived) class. Retain
2267
- // the reference type instead.
2268
- return subtype;
2269
- }
2270
- return literalType;
2271
- }
2272
- // If we're able to enumerate all possible literal values
2273
- // (for bool or enum), we can eliminate all others in a negative test.
2274
- const allLiteralTypes = enumerateLiteralsForType(evaluator, subtype);
2275
- if (allLiteralTypes && allLiteralTypes.length > 0) {
2276
- return (0, types_1.combineTypes)(allLiteralTypes.filter((type) => isPrimitiveBackedEnumComparison
2277
- ? !isLiteralValueEqualAtRuntime(type, literalType)
2278
- : !types_1.ClassType.isLiteralValueSame(type, literalType)));
2279
- }
2280
- return subtype;
2281
- }
2282
- if (isPositiveTest) {
2283
- if ((0, types_1.isClassInstance)(subtype) && types_1.ClassType.isBuiltIn(subtype, 'LiteralString')) {
2284
- return literalType;
2285
- }
2286
- if (isIsOperator || (0, typeUtils_1.isNoneInstance)(subtype)) {
2287
- const compareType = getInnermostNewTypeBaseInstance(subtype) ?? subtype;
2288
- const isSubtype = evaluator.assignType(compareType, literalType);
2289
- if (isSubtype) {
2290
- return (0, types_1.isClassInstance)(subtype) && types_1.ClassType.isNewTypeClass(subtype) ? subtype : literalType;
2291
- }
2292
- return undefined;
2293
- }
2294
- }
2295
- return subtype;
2296
- });
1198
+ return TypeEvaluatorNarrowing.narrowTypeForLiteralComparison(evaluator, referenceType, literalType, isPositiveTest, isIsOperator);
2297
1199
  }
2298
1200
  function enumerateLiteralsForType(evaluator, type) {
2299
- if (types_1.ClassType.isBuiltIn(type, 'bool')) {
2300
- // Booleans have only two types: True and False.
2301
- return [
2302
- types_1.ClassType.cloneWithLiteral(type, /* value */ true),
2303
- types_1.ClassType.cloneWithLiteral(type, /* value */ false),
2304
- ];
2305
- }
2306
- if (types_1.ClassType.isEnumClass(type)) {
2307
- // Enum expansion doesn't apply if the member set cannot be statically
2308
- // enumerated or if the class derives from enum.Flag.
2309
- if (types_1.ClassType.isEnumMemberSetMayBeDynamicallyModified(type) ||
2310
- type.shared.mro.some((mroClass) => (0, types_1.isClass)(mroClass) && types_1.ClassType.isBuiltIn(mroClass, 'Flag'))) {
2311
- return undefined;
2312
- }
2313
- // Enumerate all of the values in this enumeration.
2314
- const enumList = [];
2315
- const fields = types_1.ClassType.getSymbolTable(type);
2316
- fields.forEach((symbol, name) => {
2317
- if (!symbol.isIgnoredForProtocolMatch()) {
2318
- let symbolType = evaluator.getEffectiveTypeOfSymbol(symbol);
2319
- symbolType = (0, enums_1.transformTypeForEnumMember)(evaluator, type, name, (0, analyzerNodeInfo_1.getInfoReader)(evaluator)) ?? symbolType;
2320
- if ((0, types_1.isClassInstance)(symbolType) &&
2321
- types_1.ClassType.isSameGenericClass(type, symbolType) &&
2322
- symbolType.priv.literalValue !== undefined) {
2323
- enumList.push(symbolType);
2324
- }
2325
- }
2326
- });
2327
- return enumList;
2328
- }
2329
- return undefined;
1201
+ return TypeEvaluatorNarrowing.enumerateLiteralsForType(evaluator, type);
2330
1202
  }
2331
1203
  // Determines whether the expression name node is in the same scope or
2332
1204
  // an outer scope from the reference name node. This allows isMatchingExpression
2333
1205
  // to determine whether two name nodes are referring to the same symbol.
2334
1206
  function isNameSameScope(evaluator, reference, expression) {
2335
- const refSymbol = evaluator.lookUpSymbolRecursive(reference, reference.d.value, /* honorCodeFlow */ false);
2336
- const exprSymbol = evaluator.lookUpSymbolRecursive(expression, expression.d.value, /* honorCodeFlow */ false);
2337
- if (!refSymbol || !exprSymbol) {
2338
- // This shouldn't happen, but just to be safe...
2339
- return true;
2340
- }
2341
- const refScope = refSymbol.scope;
2342
- const exprScope = exprSymbol.scope;
2343
- if (refScope === exprScope) {
2344
- return true;
2345
- }
2346
- return (0, scopeUtils_1.isScopeContainedWithin)(refScope, exprScope);
1207
+ return TypeEvaluatorNarrowing.isNameSameScope(evaluator, reference, expression);
2347
1208
  }
2348
1209
  // Matches a reference against an expression, including the RHS of an assignment
2349
1210
  // expression. This keeps walrus narrowing consistent with truthiness handling in