@zzzen/pyright-internal 1.2.0-dev.20261011 → 1.2.0-dev.20261101

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 (144) hide show
  1. package/dist/analyzer/binder.js +28 -9
  2. package/dist/analyzer/binder.js.map +1 -1
  3. package/dist/analyzer/checker.js +8 -3
  4. package/dist/analyzer/checker.js.map +1 -1
  5. package/dist/analyzer/codeFlowEngine.js +76 -30
  6. package/dist/analyzer/codeFlowEngine.js.map +1 -1
  7. package/dist/analyzer/dataClasses.js +14 -5
  8. package/dist/analyzer/dataClasses.js.map +1 -1
  9. package/dist/analyzer/decorators.d.ts +1 -1
  10. package/dist/analyzer/decorators.js +22 -2
  11. package/dist/analyzer/decorators.js.map +1 -1
  12. package/dist/analyzer/namedTuples.d.ts +2 -1
  13. package/dist/analyzer/namedTuples.js +63 -35
  14. package/dist/analyzer/namedTuples.js.map +1 -1
  15. package/dist/analyzer/operations.js +45 -1
  16. package/dist/analyzer/operations.js.map +1 -1
  17. package/dist/analyzer/overloadResultAdmission.js +115 -3
  18. package/dist/analyzer/overloadResultAdmission.js.map +1 -1
  19. package/dist/analyzer/overloadResultController.js +36 -10
  20. package/dist/analyzer/overloadResultController.js.map +1 -1
  21. package/dist/analyzer/overloadResultSelector.js +32 -12
  22. package/dist/analyzer/overloadResultSelector.js.map +1 -1
  23. package/dist/analyzer/parseTreeUtils.d.ts +3 -0
  24. package/dist/analyzer/parseTreeUtils.js +56 -0
  25. package/dist/analyzer/parseTreeUtils.js.map +1 -1
  26. package/dist/analyzer/patternMatching.js +67 -27
  27. package/dist/analyzer/patternMatching.js.map +1 -1
  28. package/dist/analyzer/program.d.ts +3 -0
  29. package/dist/analyzer/program.js +34 -9
  30. package/dist/analyzer/program.js.map +1 -1
  31. package/dist/analyzer/sentinel.js +7 -1
  32. package/dist/analyzer/sentinel.js.map +1 -1
  33. package/dist/analyzer/service.js +6 -2
  34. package/dist/analyzer/service.js.map +1 -1
  35. package/dist/analyzer/sourceEnumerator.d.ts +3 -1
  36. package/dist/analyzer/sourceEnumerator.js +30 -11
  37. package/dist/analyzer/sourceEnumerator.js.map +1 -1
  38. package/dist/analyzer/sourceFile.js +13 -6
  39. package/dist/analyzer/sourceFile.js.map +1 -1
  40. package/dist/analyzer/sourceMapper.d.ts +1 -0
  41. package/dist/analyzer/sourceMapper.js +10 -4
  42. package/dist/analyzer/sourceMapper.js.map +1 -1
  43. package/dist/analyzer/tupleComparison.d.ts +6 -0
  44. package/dist/analyzer/tupleComparison.js +731 -0
  45. package/dist/analyzer/tupleComparison.js.map +1 -0
  46. package/dist/analyzer/tuples.js +52 -10
  47. package/dist/analyzer/tuples.js.map +1 -1
  48. package/dist/analyzer/typeEvaluator.js +508 -63
  49. package/dist/analyzer/typeEvaluator.js.map +1 -1
  50. package/dist/analyzer/typeEvaluatorTypes.d.ts +1 -1
  51. package/dist/analyzer/typeEvaluatorTypes.js +2 -3
  52. package/dist/analyzer/typeEvaluatorTypes.js.map +1 -1
  53. package/dist/analyzer/typeGuards.d.ts +6 -1
  54. package/dist/analyzer/typeGuards.js +373 -72
  55. package/dist/analyzer/typeGuards.js.map +1 -1
  56. package/dist/analyzer/typeStubRenderer.d.ts +6 -1
  57. package/dist/analyzer/typeStubRenderer.js +19 -12
  58. package/dist/analyzer/typeStubRenderer.js.map +1 -1
  59. package/dist/analyzer/typeUtils.js +3 -0
  60. package/dist/analyzer/typeUtils.js.map +1 -1
  61. package/dist/analyzer/typedDicts.d.ts +2 -1
  62. package/dist/analyzer/typedDicts.js +49 -10
  63. package/dist/analyzer/typedDicts.js.map +1 -1
  64. package/dist/analyzer/types.d.ts +14 -0
  65. package/dist/analyzer/types.js +215 -10
  66. package/dist/analyzer/types.js.map +1 -1
  67. package/dist/common/configOptions.d.ts +1 -0
  68. package/dist/common/configOptions.js +9 -0
  69. package/dist/common/configOptions.js.map +1 -1
  70. package/dist/common/processUtils.d.ts +6 -0
  71. package/dist/common/processUtils.js +56 -1
  72. package/dist/common/processUtils.js.map +1 -1
  73. package/dist/common/textEditTracker.js +1 -1
  74. package/dist/common/textEditTracker.js.map +1 -1
  75. package/dist/common/windowsProcessTree.d.ts +2 -0
  76. package/dist/common/windowsProcessTree.js +23 -0
  77. package/dist/common/windowsProcessTree.js.map +1 -1
  78. package/dist/common/windowsProcessTree.json +273 -34
  79. package/dist/languageServerBase.d.ts +3 -0
  80. package/dist/languageServerBase.js +44 -12
  81. package/dist/languageServerBase.js.map +1 -1
  82. package/dist/languageService/callHierarchyProvider.js +6 -6
  83. package/dist/languageService/callHierarchyProvider.js.map +1 -1
  84. package/dist/languageService/referencesProvider.js +3 -3
  85. package/dist/languageService/referencesProvider.js.map +1 -1
  86. package/dist/languageService/renameProvider.js +1 -1
  87. package/dist/languageService/renameProvider.js.map +1 -1
  88. package/dist/languageService/symbolIndexer.js +2 -2
  89. package/dist/languageService/symbolIndexer.js.map +1 -1
  90. package/dist/localization/localize.d.ts +2 -0
  91. package/dist/localization/localize.js +2 -0
  92. package/dist/localization/localize.js.map +1 -1
  93. package/dist/localization/package.nls.en-us.json +8 -0
  94. package/dist/parser/parseTreeTokenReuse.d.ts +34 -0
  95. package/dist/parser/parseTreeTokenReuse.js +897 -0
  96. package/dist/parser/parseTreeTokenReuse.js.map +1 -0
  97. package/dist/parser/tokenizer.d.ts +10 -1
  98. package/dist/parser/tokenizer.js +184 -130
  99. package/dist/parser/tokenizer.js.map +1 -1
  100. package/dist/tests/checker.test.js +58 -0
  101. package/dist/tests/checker.test.js.map +1 -1
  102. package/dist/tests/config.test.js +126 -0
  103. package/dist/tests/config.test.js.map +1 -1
  104. package/dist/tests/fourSlashParser.test.js +35 -0
  105. package/dist/tests/fourSlashParser.test.js.map +1 -1
  106. package/dist/tests/fourslash/hover.typedDict.get.fourslash.js +11 -0
  107. package/dist/tests/fourslash/hover.typedDict.get.fourslash.js.map +1 -1
  108. package/dist/tests/harness/fourslash/fourSlashParser.js +14 -4
  109. package/dist/tests/harness/fourslash/fourSlashParser.js.map +1 -1
  110. package/dist/tests/languageServer.test.js +15 -0
  111. package/dist/tests/languageServer.test.js.map +1 -1
  112. package/dist/tests/lsp/languageServer.js +6 -6
  113. package/dist/tests/lsp/languageServer.js.map +1 -1
  114. package/dist/tests/mypyPrimerAnalysis.test.js +133 -0
  115. package/dist/tests/mypyPrimerAnalysis.test.js.map +1 -1
  116. package/dist/tests/overloadResultController.test.js +379 -1
  117. package/dist/tests/overloadResultController.test.js.map +1 -1
  118. package/dist/tests/signatureHelp.test.js +34 -0
  119. package/dist/tests/signatureHelp.test.js.map +1 -1
  120. package/dist/tests/sourceEnumeratorSymlink.test.js +98 -13
  121. package/dist/tests/sourceEnumeratorSymlink.test.js.map +1 -1
  122. package/dist/tests/sourceMapperUtils.test.js +143 -0
  123. package/dist/tests/sourceMapperUtils.test.js.map +1 -1
  124. package/dist/tests/typeEvaluator1.test.js +22 -3
  125. package/dist/tests/typeEvaluator1.test.js.map +1 -1
  126. package/dist/tests/typeEvaluator2.test.js +54 -1
  127. package/dist/tests/typeEvaluator2.test.js.map +1 -1
  128. package/dist/tests/typeEvaluator4.test.js +10 -3
  129. package/dist/tests/typeEvaluator4.test.js.map +1 -1
  130. package/dist/tests/typeEvaluator5.test.js +1 -1
  131. package/dist/tests/typeEvaluator6.test.js +55 -0
  132. package/dist/tests/typeEvaluator6.test.js.map +1 -1
  133. package/dist/tests/typeEvaluator7.test.js +30 -0
  134. package/dist/tests/typeEvaluator7.test.js.map +1 -1
  135. package/dist/tests/typeEvaluator8.test.js +1293 -2
  136. package/dist/tests/typeEvaluator8.test.js.map +1 -1
  137. package/dist/tests/types.test.js +55 -0
  138. package/dist/tests/types.test.js.map +1 -1
  139. package/dist/typeServer/programWrapper.js +8 -2
  140. package/dist/typeServer/programWrapper.js.map +1 -1
  141. package/dist/typeServer/server.d.ts +12 -2
  142. package/dist/typeServer/server.js +97 -0
  143. package/dist/typeServer/server.js.map +1 -1
  144. package/package.json +3 -3
@@ -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;
@@ -66,6 +67,23 @@ const symbol_1 = require("./symbol");
66
67
  const typedDicts_1 = require("./typedDicts");
67
68
  const types_1 = require("./types");
68
69
  const typeUtils_1 = require("./typeUtils");
70
+ function applyTypeNarrowingCallback(callback, type) {
71
+ const result = callback(type);
72
+ const baseType = (0, types_1.getInferredTupleLiteralBase)(type);
73
+ if (baseType === type) {
74
+ return result;
75
+ }
76
+ // Narrow both views at the flow boundary, not recursively within a guard.
77
+ // Independently established literals must survive mutable inference too.
78
+ const baseResult = callback(baseType);
79
+ if (!result && !baseResult) {
80
+ return undefined;
81
+ }
82
+ return {
83
+ type: (0, types_1.retainInferredTupleLiterals)(result?.type ?? type, (0, types_1.getInferredTupleLiteralBase)(baseResult?.type ?? baseType)),
84
+ isIncomplete: !!result?.isIncomplete || !!baseResult?.isIncomplete,
85
+ };
86
+ }
69
87
  // Given a reference expression and a test expression, returns a callback that
70
88
  // can be used to narrow the type described by the reference expression.
71
89
  // If the specified flow node is not associated with the test expression,
@@ -135,37 +153,77 @@ function getTypeNarrowingCallback(evaluator, reference, testExpression, isPositi
135
153
  };
136
154
  }
137
155
  }
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
- };
156
+ // Look for "type(X) is Y", "type(X) is not Y", "type(X) == Y" or "type(X) != Y",
157
+ // as well as reverse forms "Y is type(X)", "Y is not type(X)", "Y == type(X)", "Y != type(X)".
158
+ let typeCallNode;
159
+ let otherExpr;
160
+ const isTypeCall = (expr, referenceExpr) => expr.nodeType === 9 /* ParseNodeType.Call */ &&
161
+ expr.d.args.length === 1 &&
162
+ expr.d.args[0].d.argCategory === 0 /* ArgCategory.Simple */ &&
163
+ (!referenceExpr ||
164
+ isMatchingExpressionOrWalrusRhs(evaluator, referenceExpr, expr.d.args[0].d.valueExpr)) &&
165
+ isTypeCallBase(evaluator.getTypeOfExpression(expr.d.leftExpr, 2 /* EvalFlags.CallBaseDefaults */).type);
166
+ // Either operand may be the call; pick the one whose argument matches the reference.
167
+ if (isTypeCall(testExpression.d.leftExpr, reference)) {
168
+ typeCallNode = testExpression.d.leftExpr;
169
+ otherExpr = testExpression.d.rightExpr;
170
+ }
171
+ else if (isTypeCall(testExpression.d.rightExpr, reference)) {
172
+ typeCallNode = testExpression.d.rightExpr;
173
+ otherExpr = testExpression.d.leftExpr;
174
+ }
175
+ if (typeCallNode && otherExpr) {
176
+ const otherResult = evaluator.getTypeOfExpression(otherExpr);
177
+ const classTypes = [];
178
+ let isClassType = true;
179
+ let classTypeVar;
180
+ if ((0, types_1.isTypeVar)(otherResult.type) && types_1.TypeBase.isInstantiable(otherResult.type)) {
181
+ classTypeVar = (0, typeUtils_1.convertToInstance)(otherResult.type);
182
+ }
183
+ else if ((0, types_1.isClassInstance)(otherResult.type) &&
184
+ types_1.ClassType.isBuiltIn(otherResult.type, 'type') &&
185
+ otherResult.type.priv.typeArgs?.length === 1 &&
186
+ (0, types_1.isTypeVar)(otherResult.type.priv.typeArgs[0])) {
187
+ classTypeVar = otherResult.type.priv.typeArgs[0];
188
+ }
189
+ evaluator.mapSubtypesExpandTypeVars(otherResult.type, /* options */ undefined, (expandedSubtype) => {
190
+ let instantiable;
191
+ if ((0, types_1.isClass)(expandedSubtype)) {
192
+ if ((0, types_1.isClassInstance)(expandedSubtype) &&
193
+ types_1.ClassType.isBuiltIn(expandedSubtype, 'type') &&
194
+ expandedSubtype.priv.typeArgs &&
195
+ expandedSubtype.priv.typeArgs.length > 0) {
196
+ const extracted = (0, typeUtils_1.convertToInstantiable)(expandedSubtype.priv.typeArgs[0],
197
+ /* includeSubclasses */ true);
198
+ if ((0, types_1.isInstantiableClass)(extracted)) {
199
+ instantiable = extracted;
166
200
  }
167
201
  }
202
+ else if ((0, types_1.isInstantiableClass)(expandedSubtype)) {
203
+ instantiable = expandedSubtype;
204
+ }
205
+ }
206
+ if (instantiable) {
207
+ classTypes.push(instantiable);
168
208
  }
209
+ else {
210
+ isClassType = false;
211
+ }
212
+ return undefined;
213
+ });
214
+ if (isClassType && classTypes.length > 0) {
215
+ const allowLegacyEquality = !isOrIsNotOperator &&
216
+ typeCallNode === testExpression.d.leftExpr &&
217
+ (((0, types_1.isInstantiableClass)(otherResult.type) &&
218
+ !otherResult.type.priv.includeSubclasses &&
219
+ !otherResult.type.priv.isTypeArgExplicit) ||
220
+ isTypeCall(otherExpr));
221
+ return (type) => {
222
+ return {
223
+ type: narrowTypeForTypeIs(evaluator, type, classTypes, adjIsPositiveTest, isOrIsNotOperator, classTypeVar, allowLegacyEquality),
224
+ isIncomplete: !!otherResult.isIncomplete,
225
+ };
226
+ };
169
227
  }
170
228
  }
171
229
  if (isOrIsNotOperator) {
@@ -428,9 +486,12 @@ function getTypeNarrowingCallback(evaluator, reference, testExpression, isPositi
428
486
  const isInstanceCheck = types_1.FunctionType.isBuiltIn(callType, 'isinstance');
429
487
  const arg1TypeResult = evaluator.getTypeOfExpression(arg1Expr, 536871546 /* EvalFlags.IsInstanceArgDefaults */);
430
488
  const arg1Type = arg1TypeResult.type;
431
- const classTypeList = getIsInstanceClassTypes(evaluator, arg1Type);
489
+ const classTypeInfo = getIsInstanceClassTypes(evaluator, arg1Type, arg1Expr);
432
490
  const isIncomplete = !!callTypeResult.isIncomplete || !!arg1TypeResult.isIncomplete;
433
- if (classTypeList) {
491
+ if (classTypeInfo) {
492
+ const classTypeList = isPositiveTest
493
+ ? classTypeInfo.classTypes
494
+ : classTypeInfo.negativeClassTypes;
434
495
  return (type) => {
435
496
  return {
436
497
  type: narrowTypeForInstanceOrSubclass(evaluator, type, classTypeList, isInstanceCheck,
@@ -956,23 +1017,40 @@ function narrowTypeForIsEllipsis(evaluator, node, type, isPositiveTest) {
956
1017
  }
957
1018
  return result;
958
1019
  }
959
- // The "isinstance" and "issubclass" calls support two forms - a simple form
960
- // that accepts a single class, and a more complex form that accepts a tuple
961
- // of classes (including arbitrarily-nested tuples). This method determines
962
- // which form and returns a list of classes or undefined.
963
- function getIsInstanceClassTypes(evaluator, argType) {
1020
+ // The "isinstance" and "issubclass" calls accept classes, runtime unions,
1021
+ // and arbitrarily-nested tuples of these. This method extracts possible
1022
+ // classes and guaranteed negative filters,
1023
+ // or undefined if the filter contains a non-class type.
1024
+ function getIsInstanceClassTypes(evaluator, argType, argExpr) {
964
1025
  let foundNonClassType = false;
965
- const classTypeList = [];
1026
+ const classTypes = [];
1027
+ const negativeClassTypes = [];
966
1028
  // Create a helper function that returns a list of class types or
967
1029
  // undefined if any of the types are not valid.
968
- const addClassTypesToList = (types) => {
1030
+ const addClassTypesToList = (types, isAmbiguous, isUnboundedEntry) => {
969
1031
  types.forEach((subtype) => {
970
1032
  if ((0, types_1.isClass)(subtype)) {
971
1033
  subtype = (0, typeUtils_1.specializeWithUnknownTypeArgs)(subtype, evaluator.getTupleClassType());
972
1034
  if ((0, types_1.isInstantiableClass)(subtype) && types_1.ClassType.isBuiltIn(subtype, 'Callable')) {
973
1035
  subtype = (0, typeUtils_1.convertToInstantiable)((0, typeUtils_1.getUnknownTypeForCallable)());
974
1036
  }
1037
+ else if (types_1.TypeBase.isInstance(subtype) && types_1.ClassType.isBuiltIn(subtype, 'type')) {
1038
+ if (subtype.priv.typeArgs && subtype.priv.typeArgs.length > 0) {
1039
+ const typeArg = subtype.priv.typeArgs[0];
1040
+ if ((0, types_1.isAnyOrUnknown)(typeArg)) {
1041
+ foundNonClassType = true;
1042
+ return;
1043
+ }
1044
+ if ((0, types_1.isInstantiableClass)(typeArg)) {
1045
+ subtype = types_1.ClassType.cloneIncludeSubclasses(typeArg);
1046
+ }
1047
+ else if ((0, types_1.isClassInstance)(typeArg)) {
1048
+ subtype = types_1.ClassType.cloneAsInstantiable(typeArg);
1049
+ }
1050
+ }
1051
+ }
975
1052
  }
1053
+ let classType;
976
1054
  if ((0, types_1.isInstantiableClass)(subtype)) {
977
1055
  // If this is a reference to a class that has type promotions (e.g.
978
1056
  // float or complex), remove the promotions for purposes of the
@@ -980,49 +1058,112 @@ function getIsInstanceClassTypes(evaluator, argType) {
980
1058
  if (!subtype.priv.includeSubclasses && subtype.priv.includePromotions) {
981
1059
  subtype = types_1.ClassType.cloneRemoveTypePromotions(subtype);
982
1060
  }
983
- classTypeList.push(subtype);
1061
+ classType = subtype;
984
1062
  }
985
1063
  else if ((0, types_1.isTypeVar)(subtype) && types_1.TypeBase.isInstantiable(subtype)) {
986
- classTypeList.push(subtype);
1064
+ classType = subtype;
987
1065
  }
988
1066
  else if ((0, typeUtils_1.isNoneTypeClass)(subtype)) {
989
1067
  (0, debug_1.assert)((0, types_1.isInstantiableClass)(subtype));
990
- classTypeList.push(subtype);
1068
+ classType = subtype;
991
1069
  }
992
1070
  else if ((0, types_1.isFunction)(subtype) &&
993
1071
  subtype.shared.parameters.length === 2 &&
994
1072
  subtype.shared.parameters[0].category === 1 /* ParamCategory.ArgsList */ &&
995
1073
  subtype.shared.parameters[1].category === 2 /* ParamCategory.KwargsDict */) {
996
- classTypeList.push(subtype);
1074
+ classType = subtype;
997
1075
  }
998
1076
  else {
999
1077
  foundNonClassType = true;
1078
+ return;
1079
+ }
1080
+ classTypes.push(classType);
1081
+ // Unbounded entries may be absent, and alternative class objects
1082
+ // are not all guaranteed to participate in the runtime check.
1083
+ if (!isUnboundedEntry && !isAmbiguous) {
1084
+ negativeClassTypes.push(classType);
1000
1085
  }
1001
1086
  });
1002
1087
  };
1003
- const addClassTypesRecursive = (type, recursionCount = 0) => {
1088
+ const addClassTypesRecursive = (type, isAmbiguous, isUnboundedEntry, recursionCount, expression) => {
1004
1089
  if (recursionCount > types_1.maxTypeRecursionCount) {
1005
1090
  return;
1006
1091
  }
1007
- if ((0, types_1.isClass)(type) && types_1.TypeBase.isInstance(type) && (0, typeUtils_1.isTupleClass)(type)) {
1008
- if (type.priv.tupleTypeArgs) {
1009
- type.priv.tupleTypeArgs.forEach((tupleEntry) => {
1010
- addClassTypesRecursive(tupleEntry.type, recursionCount + 1);
1011
- });
1092
+ // A runtime union checks both operands, but either operand can itself
1093
+ // be an alternative class object. Keep their certainty separate.
1094
+ if ((0, types_1.isUnion)(type) &&
1095
+ expression?.nodeType === 7 /* ParseNodeType.BinaryOperation */ &&
1096
+ expression.d.operator === 6 /* OperatorType.BitwiseOr */) {
1097
+ const leftType = evaluator.getCachedType(expression.d.leftExpr);
1098
+ const rightType = evaluator.getCachedType(expression.d.rightExpr);
1099
+ if (leftType &&
1100
+ rightType &&
1101
+ !(0, operations_1.customMetaclassSupportsMethod)(leftType, '__or__') &&
1102
+ !(0, operations_1.customMetaclassSupportsMethod)(rightType, '__ror__')) {
1103
+ // Match the union evaluator's normalization of None operands to NoneType.
1104
+ const adjustedLeftType = (0, typeUtils_1.isNoneInstance)(leftType)
1105
+ ? (0, typeUtils_1.convertToInstantiable)(evaluator.getNoneType())
1106
+ : leftType;
1107
+ const adjustedRightType = (0, typeUtils_1.isNoneInstance)(rightType)
1108
+ ? (0, typeUtils_1.convertToInstantiable)(evaluator.getNoneType())
1109
+ : rightType;
1110
+ addClassTypesRecursive(adjustedLeftType, isAmbiguous, isUnboundedEntry, recursionCount, expression.d.leftExpr);
1111
+ addClassTypesRecursive(adjustedRightType, isAmbiguous, isUnboundedEntry, recursionCount, expression.d.rightExpr);
1112
+ return;
1113
+ }
1114
+ }
1115
+ const isRuntimeUnion = type.props?.specialForm && types_1.ClassType.isBuiltIn(type.props.specialForm, 'UnionType');
1116
+ const isAmbiguousType = isAmbiguous || ((0, types_1.isUnion)(type) && !isRuntimeUnion);
1117
+ (0, typeUtils_1.doForEachSubtype)(type, (subtype) => {
1118
+ if ((0, types_1.isClassInstance)(subtype) && (0, typeUtils_1.isTupleClass)(subtype)) {
1119
+ if (subtype.priv.tupleTypeArgs) {
1120
+ let entryExpressions;
1121
+ if (expression?.nodeType === 52 /* ParseNodeType.Tuple */) {
1122
+ const expressions = [];
1123
+ expression.d.items.forEach((item) => {
1124
+ if (item.nodeType !== 56 /* ParseNodeType.Unpack */) {
1125
+ expressions.push(item);
1126
+ return;
1127
+ }
1128
+ const unpackedType = evaluator.getCachedType(item.d.expr);
1129
+ const entryCount = unpackedType && (0, types_1.isClassInstance)(unpackedType) && (0, typeUtils_1.isTupleClass)(unpackedType)
1130
+ ? unpackedType.priv.tupleTypeArgs?.length ?? 1
1131
+ : 1;
1132
+ for (let index = 0; index < entryCount; index++) {
1133
+ expressions.push(undefined);
1134
+ }
1135
+ });
1136
+ if (expressions.length === subtype.priv.tupleTypeArgs.length) {
1137
+ entryExpressions = expressions;
1138
+ }
1139
+ }
1140
+ subtype.priv.tupleTypeArgs.forEach((tupleEntry, index) => {
1141
+ addClassTypesRecursive(tupleEntry.type, isAmbiguousType, isUnboundedEntry || tupleEntry.isUnbounded, recursionCount + 1, entryExpressions?.[index]);
1142
+ });
1143
+ }
1012
1144
  }
1013
- }
1014
- else {
1015
- (0, typeUtils_1.doForEachSubtype)(type, (subtype) => {
1016
- addClassTypesToList([subtype]);
1017
- });
1018
- }
1145
+ else {
1146
+ addClassTypesToList([subtype], isAmbiguousType, isUnboundedEntry);
1147
+ }
1148
+ });
1019
1149
  };
1020
- (0, typeUtils_1.doForEachSubtype)(argType, (subtype) => {
1021
- addClassTypesRecursive(subtype);
1022
- });
1023
- return foundNonClassType ? undefined : classTypeList;
1150
+ addClassTypesRecursive(argType, /* isAmbiguous */ false, /* isUnboundedEntry */ false, 0, argExpr);
1151
+ return foundNonClassType ? undefined : { classTypes, negativeClassTypes };
1024
1152
  }
1025
1153
  function narrowTypeForInstanceOrSubclass(evaluator, type, filterTypes, isInstanceCheck, isTypeIsCheck, isPositiveTest, errorNode, nodeInfo) {
1154
+ if (!isInstanceCheck && !isTypeIsCheck && !isPositiveTest) {
1155
+ // A custom subclass check can reject even the exact same final class.
1156
+ // Preserve the existing narrowing policy for non-final classes, including ABCs.
1157
+ filterTypes = filterTypes.filter((filterType) => {
1158
+ const concreteFilterType = evaluator.makeTopLevelTypeVarsConcrete(filterType);
1159
+ return (!(0, types_1.isInstantiableClass)(concreteFilterType) ||
1160
+ !types_1.ClassType.isFinal(concreteFilterType) ||
1161
+ !(0, operations_1.customMetaclassSupportsMethod)(concreteFilterType, '__subclasscheck__'));
1162
+ });
1163
+ }
1164
+ if (!isPositiveTest && filterTypes.length === 0) {
1165
+ return type;
1166
+ }
1026
1167
  // First try with intersection types disallowed.
1027
1168
  const narrowedType = narrowTypeForInstanceOrSubclassInternal(evaluator, type, filterTypes, isInstanceCheck, isTypeIsCheck, isPositiveTest,
1028
1169
  /* allowIntersections */ false, errorNode, nodeInfo);
@@ -1162,8 +1303,10 @@ function narrowTypeForInstance(evaluator, type, filterTypes, isTypeIsCheck, isPo
1162
1303
  // note this case specially so we don't do any narrowing, which
1163
1304
  // will generate false positives.
1164
1305
  if (filterIsSuperclass) {
1165
- if (!isTypeIsCheck && concreteFilterType.priv.includeSubclasses) {
1166
- // If the filter type includes subclasses, we can't eliminate
1306
+ if (!isTypeIsCheck &&
1307
+ concreteFilterType.priv.includeSubclasses &&
1308
+ !types_1.ClassType.isFinal(concreteFilterType)) {
1309
+ // If the filter type includes subclasses and is not final, we can't eliminate
1167
1310
  // this type in the negative direction. We'll relax this for
1168
1311
  // TypeIs checks.
1169
1312
  isClassRelationshipIndeterminate = true;
@@ -1607,8 +1750,14 @@ function narrowTypeForContainerType(evaluator, referenceType, containerType, isP
1607
1750
  !containerType.priv.tupleTypeArgs) {
1608
1751
  return referenceType;
1609
1752
  }
1610
- // Determine which tuple types can be eliminated. Only "None" and
1611
- // literal types can be handled here.
1753
+ // Determine which tuple types can be eliminated. Only "None",
1754
+ // literal types, and final instantiable classes can be handled here.
1755
+ // Non-final instantiable classes (type[A]) cannot be eliminated in negative
1756
+ // tests because a subclass SubA(A) reaches the negative branch at runtime
1757
+ // (since SubA != A). Generic classes are also excluded because a
1758
+ // specialized class object like Box[int] is not the same runtime object
1759
+ // as Box. Classes that define or inherit __class_getitem__ are excluded
1760
+ // for the same reason.
1612
1761
  const typesToEliminate = [];
1613
1762
  containerType.priv.tupleTypeArgs.forEach((tupleEntry) => {
1614
1763
  if (!tupleEntry.isUnbounded) {
@@ -1618,14 +1767,23 @@ function narrowTypeForContainerType(evaluator, referenceType, containerType, isP
1618
1767
  else if ((0, types_1.isClassInstance)(tupleEntry.type) && (0, typeUtils_1.isLiteralType)(tupleEntry.type)) {
1619
1768
  typesToEliminate.push(tupleEntry.type);
1620
1769
  }
1770
+ else if ((0, types_1.isInstantiableClass)(tupleEntry.type) &&
1771
+ types_1.ClassType.isFinal(tupleEntry.type) &&
1772
+ tupleEntry.type.shared.typeParams.length === 0 &&
1773
+ !(0, typeUtils_1.lookUpClassMember)(tupleEntry.type, '__class_getitem__')) {
1774
+ typesToEliminate.push(tupleEntry.type);
1775
+ }
1621
1776
  }
1622
1777
  });
1623
1778
  if (typesToEliminate.length === 0) {
1624
1779
  return referenceType;
1625
1780
  }
1626
- return (0, typeUtils_1.mapSubtypes)(referenceType, (referenceSubtype) => {
1627
- referenceSubtype = evaluator.makeTopLevelTypeVarsConcrete(referenceSubtype);
1628
- if ((0, types_1.isClassInstance)(referenceSubtype) && referenceSubtype.priv.literalValue === undefined) {
1781
+ const canNarrowLiterals = typesToEliminate.some(types_1.isClassInstance);
1782
+ return (0, typeUtils_1.mapSubtypes)(referenceType, (unexpandedSubtype) => {
1783
+ const referenceSubtype = evaluator.makeTopLevelTypeVarsConcrete(unexpandedSubtype);
1784
+ if (canNarrowLiterals &&
1785
+ (0, types_1.isClassInstance)(referenceSubtype) &&
1786
+ referenceSubtype.priv.literalValue === undefined) {
1629
1787
  // If we're able to enumerate all possible literal values
1630
1788
  // (for bool or enum), we can eliminate all others in a negative test.
1631
1789
  const allLiteralTypes = enumerateLiteralsForType(evaluator, referenceSubtype);
@@ -1636,7 +1794,7 @@ function narrowTypeForContainerType(evaluator, referenceType, containerType, isP
1636
1794
  if (typesToEliminate.some((t) => (0, types_1.isTypeSame)(t, referenceSubtype))) {
1637
1795
  return undefined;
1638
1796
  }
1639
- return referenceSubtype;
1797
+ return unexpandedSubtype;
1640
1798
  });
1641
1799
  }
1642
1800
  function getElementTypeForContainerNarrowing(containerType) {
@@ -1906,36 +2064,172 @@ function narrowTypeForDiscriminatedFieldNoneComparison(evaluator, referenceType,
1906
2064
  return subtype;
1907
2065
  });
1908
2066
  }
2067
+ function isTypeCallBase(callType) {
2068
+ return (0, types_1.isInstantiableClass)(callType) && types_1.ClassType.isBuiltIn(callType, 'type');
2069
+ }
2070
+ // Determines whether two classes have incompatible disjoint bases (PEP 800),
2071
+ // in which case no class can derive from both of them.
2072
+ function areDisjointBasesIncompatible(classType1, classType2) {
2073
+ const base1 = types_1.ClassType.getDisjointBase(classType1);
2074
+ const base2 = types_1.ClassType.getDisjointBase(classType2);
2075
+ return !!base1 && !!base2 && !types_1.ClassType.getMostDerivedDisjointBase([base1, base2]);
2076
+ }
2077
+ // Fill gradual holes without replacing facts inferred from the guarded value.
2078
+ function fillTypeGuardGradualArgs(input, hint, results, recursionCount = 0) {
2079
+ if (!hint || input === hint || recursionCount > types_1.maxTypeRecursionCount) {
2080
+ return input;
2081
+ }
2082
+ if ((0, types_1.isAnyOrUnknown)(input)) {
2083
+ return (0, types_1.isAnyOrUnknown)(hint) ? ((0, types_1.isAny)(hint) ? hint : input) : hint;
2084
+ }
2085
+ if (!(0, types_1.isClass)(input) || !(0, types_1.isClass)(hint) || !types_1.ClassType.isSameGenericClass(input, hint)) {
2086
+ return input;
2087
+ }
2088
+ let inputResults = results.get(input);
2089
+ const cachedResult = inputResults?.get(hint);
2090
+ if (cachedResult !== undefined) {
2091
+ return cachedResult;
2092
+ }
2093
+ if (!inputResults) {
2094
+ inputResults = new Map();
2095
+ results.set(input, inputResults);
2096
+ }
2097
+ // Bound recursive aliases and reuse shared argument graphs within this narrowing operation.
2098
+ inputResults.set(hint, input);
2099
+ const inputTuple = input.priv.tupleTypeArgs;
2100
+ const hintTuple = hint.priv.tupleTypeArgs;
2101
+ if (inputTuple || hintTuple) {
2102
+ if (!inputTuple ||
2103
+ !hintTuple ||
2104
+ inputTuple.length !== hintTuple.length ||
2105
+ inputTuple.some((arg, index) => arg.isUnbounded !== hintTuple[index].isUnbounded ||
2106
+ !!arg.isOptional !== !!hintTuple[index].isOptional)) {
2107
+ return input;
2108
+ }
2109
+ const tupleArgs = inputTuple.map((arg, index) => ({
2110
+ ...arg,
2111
+ type: fillTypeGuardGradualArgs(arg.type, hintTuple[index].type, results, recursionCount + 1),
2112
+ }));
2113
+ const result = tupleArgs.every((arg, index) => arg.type === inputTuple[index].type)
2114
+ ? input
2115
+ : (0, typeUtils_1.specializeTupleClass)(input, tupleArgs, input.priv.isTypeArgExplicit, input.priv.isUnpacked);
2116
+ inputResults.set(hint, result);
2117
+ return result;
2118
+ }
2119
+ const inputArgs = input.priv.typeArgs;
2120
+ const hintArgs = hint.priv.typeArgs;
2121
+ if (!inputArgs || !hintArgs || inputArgs.length !== hintArgs.length) {
2122
+ return input;
2123
+ }
2124
+ const typeArgs = inputArgs.map((arg, index) => fillTypeGuardGradualArgs(arg, hintArgs[index], results, recursionCount + 1));
2125
+ const result = typeArgs.every((arg, index) => arg === inputArgs[index])
2126
+ ? input
2127
+ : types_1.ClassType.specialize(input, typeArgs, input.priv.isTypeArgExplicit);
2128
+ inputResults.set(hint, result);
2129
+ return result;
2130
+ }
1909
2131
  // Attempts to narrow a type based on a "type(x) is y" or "type(x) is not y" check.
1910
- function narrowTypeForTypeIs(evaluator, type, classTypes, isPositiveTest) {
2132
+ function narrowTypeForTypeIs(evaluator, type, classTypes, isPositiveTest, isIsOperator, classTypeVar, allowLegacyEquality) {
2133
+ const metaclassEqualityResults = isIsOperator ? undefined : new Map();
2134
+ const hasEqualitySemantics = allowLegacyEquality
2135
+ ? hasDeclaredIdentityEqualitySemantics
2136
+ : hasIdentityEqualitySemantics;
2137
+ if (metaclassEqualityResults &&
2138
+ classTypes.some((classType) => !hasEqualitySemantics(classType, metaclassEqualityResults))) {
2139
+ return type;
2140
+ }
1911
2141
  // We currently don't support narrowing in the negative direction
1912
2142
  // when there are more than one class types.
1913
2143
  if (!isPositiveTest && classTypes.length > 1) {
1914
2144
  return type;
1915
2145
  }
2146
+ // Retain the TypeVar rather than its expanded constraints so assignments and loop joins preserve correlation.
2147
+ if (isIsOperator && isPositiveTest && classTypeVar && (0, types_1.isAnyOrUnknown)(type)) {
2148
+ return classTypeVar;
2149
+ }
2150
+ let gradualArgResults;
1916
2151
  const typesToCombine = classTypes.map((classType) => {
1917
2152
  return evaluator.mapSubtypesExpandTypeVars(type,
1918
2153
  /* options */ undefined, (subtype, unexpandedSubtype) => {
1919
2154
  if ((0, types_1.isClassInstance)(subtype)) {
1920
- const matches = types_1.ClassType.isDerivedFrom(classType, types_1.ClassType.cloneAsInstantiable(subtype));
2155
+ const isLiteral = subtype.priv.literalValue !== undefined;
2156
+ const instantiableSubtype = isLiteral
2157
+ ? types_1.ClassType.cloneIncludeSubclasses(types_1.ClassType.cloneAsInstantiable(types_1.ClassType.cloneWithLiteral(subtype, undefined)),
2158
+ /* includeSubclasses */ false)
2159
+ : types_1.ClassType.cloneAsInstantiable(subtype);
2160
+ if (metaclassEqualityResults &&
2161
+ !hasEqualitySemantics(instantiableSubtype, metaclassEqualityResults)) {
2162
+ return unexpandedSubtype;
2163
+ }
2164
+ const matches = types_1.ClassType.isDerivedFrom(classType, instantiableSubtype);
2165
+ // A literal has an exact runtime class, not an arbitrary subclass.
2166
+ if (matches && isLiteral && !types_1.ClassType.isSameGenericClass(instantiableSubtype, classType)) {
2167
+ return isPositiveTest ? undefined : subtype;
2168
+ }
1921
2169
  if (isPositiveTest) {
1922
2170
  if (matches) {
1923
- if (types_1.ClassType.isSameGenericClass(types_1.ClassType.cloneAsInstantiable(subtype), classType)) {
2171
+ if (types_1.ClassType.isSameGenericClass(instantiableSubtype, classType)) {
1924
2172
  return (0, typeUtils_1.addConditionToType)(subtype, (0, typeUtils_1.getTypeCondition)(classType));
1925
2173
  }
1926
- return (0, typeUtils_1.addConditionToType)(types_1.ClassType.cloneAsInstance(classType), subtype.props?.condition);
2174
+ let narrowedClass = classType;
2175
+ if (subtype.priv.typeArgs || subtype.priv.tupleTypeArgs) {
2176
+ if (classType.shared.typeParams.length > 0) {
2177
+ if ((0, typeUtils_1.containsAnyRecursive)(classType) ||
2178
+ !evaluator.assignType(subtype, types_1.ClassType.cloneAsInstance(classType))) {
2179
+ const genericClass = (0, typeUtils_1.selfSpecializeClass)(types_1.ClassType.specialize(classType, undefined));
2180
+ const constraints = new constraintTracker_1.ConstraintTracker();
2181
+ if (!evaluator.assignType(subtype, types_1.ClassType.cloneAsInstance(genericClass), undefined, constraints, 2 /* AssignTypeFlags.Contravariant */ |
2182
+ 2048 /* AssignTypeFlags.PopulateExpectedType */ |
2183
+ 4096 /* AssignTypeFlags.SkipPopulateUnknownExpectedType */)) {
2184
+ return (0, typeUtils_1.addConditionToType)(subtype, (0, typeUtils_1.getTypeCondition)(classType));
2185
+ }
2186
+ const specializedClass = evaluator.solveAndApplyConstraints(genericClass, constraints, {
2187
+ replaceUnsolved: {
2188
+ scopeIds: (0, typeUtils_1.getTypeVarScopeIds)(classType),
2189
+ useUnknown: true,
2190
+ tupleClassType: evaluator.getTupleClassType(),
2191
+ },
2192
+ });
2193
+ if (!(0, types_1.isInstantiableClass)(specializedClass)) {
2194
+ return (0, typeUtils_1.addConditionToType)(subtype, (0, typeUtils_1.getTypeCondition)(classType));
2195
+ }
2196
+ const results = (gradualArgResults ?? (gradualArgResults = new Map()));
2197
+ narrowedClass = types_1.ClassType.specialize(specializedClass, specializedClass.priv.typeArgs?.map((arg, index) => fillTypeGuardGradualArgs(arg, classType.priv.typeArgs?.[index], results)));
2198
+ }
2199
+ }
2200
+ else if (!evaluator.assignType(subtype, types_1.ClassType.cloneAsInstance(classType))) {
2201
+ return classType.priv.includeSubclasses && !types_1.ClassType.isFinal(classType)
2202
+ ? (0, typeUtils_1.addConditionToType)(subtype, (0, typeUtils_1.getTypeCondition)(classType))
2203
+ : undefined;
2204
+ }
2205
+ }
2206
+ return (0, typeUtils_1.addConditionToType)(types_1.ClassType.cloneAsInstance(narrowedClass), subtype.props?.condition);
1927
2207
  }
1928
2208
  if (!classType.priv.includeSubclasses) {
2209
+ if (evaluator.assignType(subtype, types_1.ClassType.cloneAsInstance(classType))) {
2210
+ return (0, typeUtils_1.addConditionToType)(types_1.ClassType.cloneAsInstance(classType), (0, typeUtils_1.getTypeCondition)(subtype));
2211
+ }
2212
+ return undefined;
2213
+ }
2214
+ // A subclass of both the subtype and the class could satisfy the
2215
+ // comparison, so eliminate the subtype only if no such class can exist.
2216
+ if ((types_1.ClassType.isFinal(classType) ||
2217
+ isLiteral ||
2218
+ types_1.ClassType.isFinal(instantiableSubtype) ||
2219
+ areDisjointBasesIncompatible(instantiableSubtype, classType)) &&
2220
+ !evaluator.assignType(types_1.ClassType.cloneAsInstance(classType), subtype) &&
2221
+ !evaluator.assignType(subtype, types_1.ClassType.cloneAsInstance(classType))) {
1929
2222
  return undefined;
1930
2223
  }
1931
2224
  if (!(0, types_1.isTypeVar)(unexpandedSubtype) || !types_1.TypeVarType.isSelf(unexpandedSubtype)) {
1932
2225
  return (0, typeUtils_1.addConditionToType)(subtype, classType.props?.condition);
1933
2226
  }
1934
2227
  }
1935
- if (!classType.priv.includeSubclasses) {
1936
- // If the class if marked final and it matches, then
2228
+ // A final class has no subclasses, so it is treated as an exact class.
2229
+ if (!classType.priv.includeSubclasses || types_1.ClassType.isFinal(classType)) {
2230
+ // If the runtime class is exact and it matches, then
1937
2231
  // we can eliminate it in the negative case.
1938
- if (matches && types_1.ClassType.isFinal(subtype)) {
2232
+ if (matches && (isLiteral || types_1.ClassType.isFinal(instantiableSubtype))) {
1939
2233
  return undefined;
1940
2234
  }
1941
2235
  // We can't eliminate the subtype in the negative
@@ -1945,6 +2239,9 @@ function narrowTypeForTypeIs(evaluator, type, classTypes, isPositiveTest) {
1945
2239
  }
1946
2240
  }
1947
2241
  if ((0, types_1.isAnyOrUnknown)(subtype)) {
2242
+ if (metaclassEqualityResults && !allowLegacyEquality) {
2243
+ return subtype;
2244
+ }
1948
2245
  return isPositiveTest
1949
2246
  ? types_1.ClassType.cloneAsInstance((0, typeUtils_1.addConditionToType)(classType, (0, typeUtils_1.getTypeCondition)(subtype)))
1950
2247
  : subtype;
@@ -1969,6 +2266,10 @@ function hasIdentityEqualitySemantics(classType, metaclassEqualityResults) {
1969
2266
  if (classType.shared.typeParams.length > 0) {
1970
2267
  return false;
1971
2268
  }
2269
+ return hasDeclaredIdentityEqualitySemantics(classType, metaclassEqualityResults);
2270
+ }
2271
+ // Legacy forward type(x) equality guards check declared metaclasses without closing subclass hierarchies.
2272
+ function hasDeclaredIdentityEqualitySemantics(classType, metaclassEqualityResults) {
1972
2273
  const metaclass = classType.shared.effectiveMetaclass;
1973
2274
  if (!metaclass ||
1974
2275
  !(0, types_1.isInstantiableClass)(metaclass) ||