@zzzen/pyright-internal 1.2.0-dev.20250309 → 1.2.0-dev.20250323

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 (107) hide show
  1. package/dist/analyzer/analyzerFileInfo.d.ts +1 -0
  2. package/dist/analyzer/analyzerFileInfo.js.map +1 -1
  3. package/dist/analyzer/binder.js +21 -13
  4. package/dist/analyzer/binder.js.map +1 -1
  5. package/dist/analyzer/checker.d.ts +3 -0
  6. package/dist/analyzer/checker.js +58 -9
  7. package/dist/analyzer/checker.js.map +1 -1
  8. package/dist/analyzer/codeFlowTypes.d.ts +2 -2
  9. package/dist/analyzer/codeFlowTypes.js +9 -0
  10. package/dist/analyzer/codeFlowTypes.js.map +1 -1
  11. package/dist/analyzer/constructorTransform.js +1 -1
  12. package/dist/analyzer/constructorTransform.js.map +1 -1
  13. package/dist/analyzer/constructors.js +7 -1
  14. package/dist/analyzer/constructors.js.map +1 -1
  15. package/dist/analyzer/declaration.d.ts +1 -1
  16. package/dist/analyzer/declaration.js.map +1 -1
  17. package/dist/analyzer/importResolver.d.ts +2 -0
  18. package/dist/analyzer/importResolver.js +29 -6
  19. package/dist/analyzer/importResolver.js.map +1 -1
  20. package/dist/analyzer/importResult.d.ts +1 -0
  21. package/dist/analyzer/operations.js +10 -2
  22. package/dist/analyzer/operations.js.map +1 -1
  23. package/dist/analyzer/parameterUtils.d.ts +15 -0
  24. package/dist/analyzer/parameterUtils.js +59 -1
  25. package/dist/analyzer/parameterUtils.js.map +1 -1
  26. package/dist/analyzer/parseTreeUtils.d.ts +2 -0
  27. package/dist/analyzer/parseTreeUtils.js +19 -0
  28. package/dist/analyzer/parseTreeUtils.js.map +1 -1
  29. package/dist/analyzer/program.js +17 -4
  30. package/dist/analyzer/program.js.map +1 -1
  31. package/dist/analyzer/programTypes.d.ts +2 -2
  32. package/dist/analyzer/programTypes.js.map +1 -1
  33. package/dist/analyzer/service.d.ts +3 -3
  34. package/dist/analyzer/service.js +16 -6
  35. package/dist/analyzer/service.js.map +1 -1
  36. package/dist/analyzer/sourceFile.d.ts +2 -1
  37. package/dist/analyzer/sourceFile.js +3 -1
  38. package/dist/analyzer/sourceFile.js.map +1 -1
  39. package/dist/analyzer/typeEvaluator.js +236 -245
  40. package/dist/analyzer/typeEvaluator.js.map +1 -1
  41. package/dist/analyzer/typeEvaluatorTypes.d.ts +3 -1
  42. package/dist/analyzer/typeEvaluatorTypes.js.map +1 -1
  43. package/dist/analyzer/typeUtils.js +8 -7
  44. package/dist/analyzer/typeUtils.js.map +1 -1
  45. package/dist/analyzer/typeWalker.js +1 -1
  46. package/dist/analyzer/typeWalker.js.map +1 -1
  47. package/dist/analyzer/types.d.ts +6 -5
  48. package/dist/analyzer/types.js +15 -23
  49. package/dist/analyzer/types.js.map +1 -1
  50. package/dist/common/cancellationUtils.d.ts +3 -0
  51. package/dist/common/cancellationUtils.js +8 -1
  52. package/dist/common/cancellationUtils.js.map +1 -1
  53. package/dist/common/languageServerInterface.d.ts +0 -2
  54. package/dist/common/languageServerInterface.js.map +1 -1
  55. package/dist/common/serviceKeys.d.ts +2 -0
  56. package/dist/common/serviceKeys.js +1 -0
  57. package/dist/common/serviceKeys.js.map +1 -1
  58. package/dist/common/serviceProviderExtensions.d.ts +2 -0
  59. package/dist/common/serviceProviderExtensions.js +9 -2
  60. package/dist/common/serviceProviderExtensions.js.map +1 -1
  61. package/dist/languageServerBase.d.ts +7 -3
  62. package/dist/languageServerBase.js +126 -5
  63. package/dist/languageServerBase.js.map +1 -1
  64. package/dist/languageService/tooltipUtils.js +2 -2
  65. package/dist/languageService/tooltipUtils.js.map +1 -1
  66. package/dist/localization/package.nls.cs.json +1 -1
  67. package/dist/localization/package.nls.de.json +1 -1
  68. package/dist/localization/package.nls.es.json +1 -1
  69. package/dist/localization/package.nls.fr.json +1 -1
  70. package/dist/localization/package.nls.it.json +1 -1
  71. package/dist/localization/package.nls.ja.json +1 -1
  72. package/dist/localization/package.nls.ko.json +1 -1
  73. package/dist/localization/package.nls.pl.json +1 -1
  74. package/dist/localization/package.nls.pt-br.json +1 -1
  75. package/dist/localization/package.nls.ru.json +1 -1
  76. package/dist/localization/package.nls.tr.json +1 -1
  77. package/dist/localization/package.nls.zh-cn.json +1 -1
  78. package/dist/localization/package.nls.zh-tw.json +1 -1
  79. package/dist/pyright.js +9 -3
  80. package/dist/pyright.js.map +1 -1
  81. package/dist/readonlyAugmentedFileSystem.js +4 -0
  82. package/dist/readonlyAugmentedFileSystem.js.map +1 -1
  83. package/dist/server.js +1 -2
  84. package/dist/server.js.map +1 -1
  85. package/dist/tests/checker.test.js +11 -0
  86. package/dist/tests/checker.test.js.map +1 -1
  87. package/dist/tests/fourslash/import.pytyped.privateSymbols.fourslash.js +18 -0
  88. package/dist/tests/fourslash/import.pytyped.privateSymbols.fourslash.js.map +1 -1
  89. package/dist/tests/languageServer.test.js +97 -57
  90. package/dist/tests/languageServer.test.js.map +1 -1
  91. package/dist/tests/lsp/customLsp.d.ts +8 -1
  92. package/dist/tests/lsp/customLsp.js +1 -0
  93. package/dist/tests/lsp/customLsp.js.map +1 -1
  94. package/dist/tests/lsp/languageServer.js +12 -0
  95. package/dist/tests/lsp/languageServer.js.map +1 -1
  96. package/dist/tests/lsp/languageServerTestUtils.d.ts +7 -3
  97. package/dist/tests/lsp/languageServerTestUtils.js +90 -6
  98. package/dist/tests/lsp/languageServerTestUtils.js.map +1 -1
  99. package/dist/tests/sourceFile.test.js +5 -4
  100. package/dist/tests/sourceFile.test.js.map +1 -1
  101. package/dist/tests/typeEvaluator1.test.js +6 -2
  102. package/dist/tests/typeEvaluator1.test.js.map +1 -1
  103. package/dist/tests/typeEvaluator4.test.js +1 -1
  104. package/dist/tests/typeEvaluator5.test.js +1 -1
  105. package/dist/tests/typeEvaluator6.test.js +1 -1
  106. package/dist/types.d.ts +6 -2
  107. package/package.json +1 -1
@@ -142,6 +142,10 @@ const maxCallSiteReturnTypeCacheSize = 8;
142
142
  // when inferring the type? We need to cut it off at some point
143
143
  // to avoid excessive computation.
144
144
  const maxEntriesToUseForInference = 64;
145
+ // How many times should attempt to infer a return type of a
146
+ // function before giving up and assuming that it won't converge
147
+ // due to recursion?
148
+ const maxReturnTypeInferenceAttempts = 8;
145
149
  // How many assignments to an unannotated variable should be used
146
150
  // when inferring its type? We need to cut it off at some point
147
151
  // to avoid excessive computation.
@@ -194,7 +198,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
194
198
  let deferredClassCompletions = [];
195
199
  let cancellationToken;
196
200
  let printExpressionSpaceCount = 0;
197
- let incompleteGenerationCount = 0;
201
+ let incompleteGenCount = 0;
198
202
  const returnTypeInferenceContextStack = [];
199
203
  let returnTypeInferenceTypeCache;
200
204
  const signatureTrackerStack = [];
@@ -255,7 +259,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
255
259
  if (!cacheEntry) {
256
260
  return false;
257
261
  }
258
- return (!cacheEntry.typeResult.isIncomplete || cacheEntry.incompleteGenerationCount === incompleteGenerationCount);
262
+ return !cacheEntry.typeResult.isIncomplete || cacheEntry.incompleteGenCount === incompleteGenCount;
259
263
  }
260
264
  function readTypeCache(node, flags) {
261
265
  const cacheEntry = readTypeCacheEntry(node);
@@ -290,22 +294,22 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
290
294
  ? returnTypeInferenceTypeCache
291
295
  : typeCache;
292
296
  if (!typeResult.isIncomplete) {
293
- incompleteGenerationCount++;
297
+ incompleteGenCount++;
294
298
  }
295
299
  else {
296
300
  const oldValue = typeCacheToUse.get(node.id);
297
301
  if (oldValue !== undefined && !(0, types_1.isTypeSame)(typeResult.type, oldValue.typeResult.type)) {
298
- incompleteGenerationCount++;
302
+ incompleteGenCount++;
299
303
  }
300
304
  }
301
- typeCacheToUse.set(node.id, { typeResult, flags, incompleteGenerationCount: incompleteGenerationCount });
305
+ typeCacheToUse.set(node.id, { typeResult, flags, incompleteGenCount });
302
306
  // If the entry is located within a part of the parse tree that is currently being
303
307
  // "speculatively" evaluated, track it so we delete the cached entry when we leave
304
308
  // this speculative context.
305
309
  if (isSpeculativeModeInUse(node)) {
306
310
  speculativeTypeTracker.trackEntry(typeCacheToUse, node.id);
307
311
  if (allowSpeculativeCaching) {
308
- speculativeTypeTracker.addSpeculativeType(node, typeResult, incompleteGenerationCount, inferenceContext?.expectedType);
312
+ speculativeTypeTracker.addSpeculativeType(node, typeResult, incompleteGenCount, inferenceContext?.expectedType);
309
313
  }
310
314
  }
311
315
  }
@@ -531,23 +535,23 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
531
535
  function getTypeOfExpression(node, flags = 0 /* EvalFlags.None */, inferenceContext) {
532
536
  // Is this type already cached?
533
537
  const cacheEntry = readTypeCacheEntry(node);
534
- if (cacheEntry &&
535
- (!cacheEntry.typeResult.isIncomplete || cacheEntry.incompleteGenerationCount === incompleteGenerationCount)) {
536
- if (printExpressionTypes) {
537
- console.log(`${getPrintExpressionTypesSpaces()}${ParseTreeUtils.printExpression(node)} (${getLineNum(node)}): Cached ${printType(cacheEntry.typeResult.type)} ${cacheEntry.typeResult.typeErrors ? ' Errors' : ''}`);
538
+ if (cacheEntry) {
539
+ if (!cacheEntry.typeResult.isIncomplete || cacheEntry.incompleteGenCount === incompleteGenCount) {
540
+ if (printExpressionTypes) {
541
+ console.log(`${getPrintExpressionTypesSpaces()}${ParseTreeUtils.printExpression(node)} (${getLineNum(node)}): Cached ${printType(cacheEntry.typeResult.type)} ${cacheEntry.typeResult.typeErrors ? ' Errors' : ''}`);
542
+ }
543
+ return cacheEntry.typeResult;
538
544
  }
539
- return cacheEntry.typeResult;
540
545
  }
541
- else {
542
- // Is it cached in the speculative type cache?
543
- const cacheEntry = speculativeTypeTracker.getSpeculativeType(node, inferenceContext?.expectedType);
544
- if (cacheEntry &&
545
- (!cacheEntry.typeResult.isIncomplete ||
546
- cacheEntry.incompleteGenerationCount === incompleteGenerationCount)) {
546
+ // Is it cached in the speculative type cache?
547
+ const specCacheEntry = speculativeTypeTracker.getSpeculativeType(node, inferenceContext?.expectedType);
548
+ if (specCacheEntry) {
549
+ if (!specCacheEntry.typeResult.isIncomplete ||
550
+ specCacheEntry.incompleteGenerationCount === incompleteGenCount) {
547
551
  if (printExpressionTypes) {
548
- console.log(`${getPrintExpressionTypesSpaces()}${ParseTreeUtils.printExpression(node)} (${getLineNum(node)}): Speculative ${printType(cacheEntry.typeResult.type)}`);
552
+ console.log(`${getPrintExpressionTypesSpaces()}${ParseTreeUtils.printExpression(node)} (${getLineNum(node)}): Speculative ${printType(specCacheEntry.typeResult.type)}`);
549
553
  }
550
- return cacheEntry.typeResult;
554
+ return specCacheEntry.typeResult;
551
555
  }
552
556
  }
553
557
  if (printExpressionTypes) {
@@ -2355,7 +2359,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
2355
2359
  }
2356
2360
  else {
2357
2361
  // Constrain the resulting type to match the declared type.
2358
- destType = narrowTypeBasedOnAssignment(nameNode, declaredType, typeResult).type;
2362
+ destType = narrowTypeBasedOnAssignment(declaredType, typeResult).type;
2359
2363
  }
2360
2364
  }
2361
2365
  else {
@@ -2950,7 +2954,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
2950
2954
  // is a enum because the annotated type in an enum doesn't reflect
2951
2955
  // the type of the symbol.
2952
2956
  if (!(0, types_1.isClassInstance)(typeResult.type) || !types_1.ClassType.isEnumClass(typeResult.type)) {
2953
- typeResult = narrowTypeBasedOnAssignment(target, annotationType, typeResult);
2957
+ typeResult = narrowTypeBasedOnAssignment(annotationType, typeResult);
2954
2958
  }
2955
2959
  }
2956
2960
  }
@@ -3958,8 +3962,9 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
3958
3962
  if (isModuleGetAttrSupported) {
3959
3963
  const getAttrTypeResult = getEffectiveTypeOfSymbolForUsage(getAttrSymbol);
3960
3964
  if ((0, types_1.isFunction)(getAttrTypeResult.type)) {
3961
- type = getEffectiveReturnType(getAttrTypeResult.type);
3962
- if (getAttrTypeResult.isIncomplete) {
3965
+ const returnTypeResult = getEffectiveReturnTypeResult(getAttrTypeResult.type);
3966
+ type = returnTypeResult.type;
3967
+ if (getAttrTypeResult.isIncomplete || returnTypeResult.isIncomplete) {
3963
3968
  isIncomplete = true;
3964
3969
  }
3965
3970
  }
@@ -4310,7 +4315,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
4310
4315
  // descriptor-based accesses.
4311
4316
  narrowedTypeForSet = isDescriptorApplied
4312
4317
  ? usage.setType.type
4313
- : narrowTypeBasedOnAssignment(errorNode, type, usage.setType).type;
4318
+ : narrowTypeBasedOnAssignment(type, usage.setType).type;
4314
4319
  }
4315
4320
  // Verify that the assigned type is compatible.
4316
4321
  if (!assignType(type, usage.setType.type, diag?.createAddendum())) {
@@ -6399,7 +6404,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
6399
6404
  // list will grow to include union expansions.
6400
6405
  function validateOverloadsWithExpandedTypes(errorNode, expandedArgTypes, argParamMatches, constraints, skipUnknownArgCheck, inferenceContext) {
6401
6406
  const returnTypes = [];
6402
- const matchedOverloads = [];
6407
+ let matchedOverloads = [];
6403
6408
  let isTypeIncomplete = false;
6404
6409
  let overloadsUsedForCall = [];
6405
6410
  let isDefinitiveMatchFound = false;
@@ -6447,10 +6452,12 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
6447
6452
  argResults: callResult.argResults ?? [],
6448
6453
  };
6449
6454
  matchedOverloads.push(matchedOverloadInfo);
6450
- if (callResult.anyOrUnknownArg) {
6455
+ if (callResult.anyOrUnknownArg || matchResults.unpackedArgOfUnknownLength) {
6451
6456
  possibleMatchResults.push(matchedOverloadInfo);
6452
- if ((0, typeUtils_1.isIncompleteUnknown)(callResult.anyOrUnknownArg)) {
6453
- possibleMatchInvolvesIncompleteUnknown = true;
6457
+ if (callResult.anyOrUnknownArg) {
6458
+ if ((0, typeUtils_1.isIncompleteUnknown)(callResult.anyOrUnknownArg)) {
6459
+ possibleMatchInvolvesIncompleteUnknown = true;
6460
+ }
6454
6461
  }
6455
6462
  }
6456
6463
  else {
@@ -6466,11 +6473,13 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
6466
6473
  // Unknown, but include the "possible types" to allow for completion
6467
6474
  // suggestions.
6468
6475
  if (!isDefinitiveMatchFound && possibleMatchResults.length > 0) {
6476
+ possibleMatchResults = filterOverloadMatchesForUnpackedArgs(possibleMatchResults);
6469
6477
  possibleMatchResults = filterOverloadMatchesForAnyArgs(possibleMatchResults);
6470
6478
  // Did the filtering produce a single result? If so, we're done.
6471
6479
  if (possibleMatchResults.length === 1) {
6472
6480
  overloadsUsedForCall = [possibleMatchResults[0].overload];
6473
6481
  returnTypes.push(possibleMatchResults[0].returnType);
6482
+ matchedOverloads = [possibleMatchResults[0]];
6474
6483
  }
6475
6484
  else {
6476
6485
  // Eliminate any return types that are subsumed by other return types.
@@ -6551,21 +6560,26 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
6551
6560
  overloadsUsedForCall,
6552
6561
  };
6553
6562
  }
6554
- // This function determines whether multiple incompatible overloads match
6563
+ // Determines whether one or more overloads can be eliminated because they
6564
+ // rely on an unpacked argument of unknown length when there is at least
6565
+ // one overload that doesn't because it maps to an *args parameter.
6566
+ function filterOverloadMatchesForUnpackedArgs(matches) {
6567
+ if (matches.length < 2) {
6568
+ return matches;
6569
+ }
6570
+ // Is there at least one overload that relies on unpacked args for a match?
6571
+ const unpackedArgsOverloads = matches.filter((match) => match.matchResults.unpackedArgMapsToVariadic);
6572
+ if (unpackedArgsOverloads.length === matches.length || unpackedArgsOverloads.length === 0) {
6573
+ return matches;
6574
+ }
6575
+ return unpackedArgsOverloads;
6576
+ }
6577
+ // Determines whether multiple incompatible overloads match
6555
6578
  // due to an Any or Unknown argument type.
6556
6579
  function filterOverloadMatchesForAnyArgs(matches) {
6557
6580
  if (matches.length < 2) {
6558
6581
  return matches;
6559
6582
  }
6560
- // If the relevance of some matches differs, filter out the ones that
6561
- // are lower relevance. This favors *args parameters in cases where
6562
- // a *args argument is used.
6563
- if (matches[0].matchResults.relevance !== matches[matches.length - 1].matchResults.relevance) {
6564
- matches = matches.filter((m) => m.matchResults.relevance === matches[0].matchResults.relevance);
6565
- if (matches.length < 2) {
6566
- return matches;
6567
- }
6568
- }
6569
6583
  // If all of the return types match, select the first one.
6570
6584
  if ((0, typeUtils_1.areTypesSame)(matches.map((match) => match.returnType), { treatAnySameAsUnknown: true })) {
6571
6585
  return [matches[0]];
@@ -6599,7 +6613,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
6599
6613
  }
6600
6614
  function getBestOverloadForArgs(errorNode, typeResult, argList) {
6601
6615
  let overloadIndex = 0;
6602
- let matches = [];
6616
+ const matches = [];
6603
6617
  const speculativeNode = getSpeculativeNodeForCall(errorNode);
6604
6618
  useSignatureTracker(errorNode, () => {
6605
6619
  // Create a list of potential overload matches based on arguments.
@@ -6613,7 +6627,6 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
6613
6627
  });
6614
6628
  });
6615
6629
  });
6616
- matches = sortOverloadsByBestMatch(matches);
6617
6630
  let winningOverloadIndex;
6618
6631
  matches.forEach((match, matchIndex) => {
6619
6632
  if (winningOverloadIndex === undefined) {
@@ -6628,17 +6641,8 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
6628
6641
  });
6629
6642
  return winningOverloadIndex === undefined ? undefined : matches[winningOverloadIndex].overload;
6630
6643
  }
6631
- // Sorts the list of overloads based first on "relevance" and second on order.
6632
- function sortOverloadsByBestMatch(matches) {
6633
- return matches.sort((a, b) => {
6634
- if (a.relevance !== b.relevance) {
6635
- return b.relevance - a.relevance;
6636
- }
6637
- return a.overloadIndex - b.overloadIndex;
6638
- });
6639
- }
6640
6644
  function validateOverloadedArgTypes(errorNode, argList, typeResult, constraints, skipUnknownArgCheck, inferenceContext) {
6641
- let filteredMatchResults = [];
6645
+ const filteredMatchResults = [];
6642
6646
  let contextFreeArgTypes;
6643
6647
  let isTypeIncomplete = !!typeResult.isIncomplete;
6644
6648
  const type = typeResult.type;
@@ -6661,7 +6665,6 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
6661
6665
  overloadIndex++;
6662
6666
  });
6663
6667
  });
6664
- filteredMatchResults = sortOverloadsByBestMatch(filteredMatchResults);
6665
6668
  // If there are no possible arg/param matches among the overloads,
6666
6669
  // emit an error that includes the argument types.
6667
6670
  if (filteredMatchResults.length === 0) {
@@ -6904,11 +6907,12 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
6904
6907
  case 3 /* TypeCategory.Never */:
6905
6908
  case 1 /* TypeCategory.Unknown */:
6906
6909
  case 2 /* TypeCategory.Any */: {
6907
- // Touch all of the args so they're marked accessed. Don't bother
6908
- // doing this if the call type is incomplete because this will need
6909
- // to be done again once it is complete.
6910
- touchArgTypes();
6911
- return { returnType: expandedCallType };
6910
+ // Create a dummy callable that accepts all arguments and validate
6911
+ // that the argument expressions are valid.
6912
+ const dummyFunctionType = types_1.FunctionType.createInstance('', '', '', 0 /* FunctionTypeFlags.None */);
6913
+ types_1.FunctionType.addDefaultParams(dummyFunctionType);
6914
+ const dummyCallResult = validateCallForFunction(errorNode, argList, dummyFunctionType, isCallTypeIncomplete, constraints, skipUnknownArgCheck, inferenceContext);
6915
+ return { ...dummyCallResult, returnType: expandedCallType };
6912
6916
  }
6913
6917
  case 4 /* TypeCategory.Function */: {
6914
6918
  return validateCallForFunction(errorNode, argList, expandedCallType, isCallTypeIncomplete, constraints, skipUnknownArgCheck, inferenceContext);
@@ -6919,6 +6923,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
6919
6923
  case 6 /* TypeCategory.Class */: {
6920
6924
  if ((0, typeUtils_1.isNoneInstance)(expandedCallType)) {
6921
6925
  addDiagnostic(diagnosticRules_1.DiagnosticRule.reportOptionalCall, localize_1.LocMessage.noneNotCallable(), errorNode);
6926
+ touchArgTypes();
6922
6927
  return { argumentErrors: true };
6923
6928
  }
6924
6929
  if (types_1.TypeBase.isInstantiable(expandedCallType)) {
@@ -6935,6 +6940,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
6935
6940
  }
6936
6941
  case 7 /* TypeCategory.Module */: {
6937
6942
  addDiagnostic(diagnosticRules_1.DiagnosticRule.reportCallIssue, localize_1.LocMessage.moduleNotCallable(), errorNode);
6943
+ touchArgTypes();
6938
6944
  return { argumentErrors: true };
6939
6945
  }
6940
6946
  }
@@ -7397,25 +7403,15 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7397
7403
  const paramDetails = (0, parameterUtils_1.getParamListDetails)(overload, { disallowExtraKwargsForTd: true });
7398
7404
  const paramSpec = types_1.FunctionType.getParamSpecFromArgsKwargs(overload);
7399
7405
  let argIndex = 0;
7400
- let matchedUnpackedListOfUnknownLength = false;
7406
+ let unpackedArgOfUnknownLength = false;
7407
+ let unpackedArgMapsToVariadic = false;
7401
7408
  let reportedArgError = false;
7402
7409
  let isTypeIncomplete = !!typeResult.isIncomplete;
7403
7410
  let isTypeVarTupleFullyMatched = false;
7404
7411
  // Expand any unpacked tuples in the arg list.
7405
7412
  argList = expandArgList(argList);
7406
- // Build a map of parameters by name.
7407
- const paramMap = new Map();
7408
- paramDetails.params.forEach((paramInfo) => {
7409
- (0, debug_1.assert)(paramInfo !== undefined, 'paramInfo is undefined for param name map');
7410
- const param = paramInfo.param;
7411
- if (param.name && param.category === 0 /* ParamCategory.Simple */ && paramInfo.kind !== parameterUtils_1.ParamKind.Positional) {
7412
- let argsNeeded = paramMap.get(param.name)?.argsNeeded ?? 0;
7413
- if (param.category === 0 /* ParamCategory.Simple */ && !paramInfo.defaultType) {
7414
- argsNeeded += 1;
7415
- }
7416
- paramMap.set(param.name, { argsNeeded, argsReceived: 0 });
7417
- }
7418
- });
7413
+ // Construct an object that racks which parameters have been assigned arguments.
7414
+ const paramTracker = new parameterUtils_1.ParamAssignmentTracker(paramDetails.params);
7419
7415
  let positionalOnlyLimitIndex = paramDetails.positionOnlyParamCount;
7420
7416
  let positionParamLimitIndex = paramDetails.firstKeywordOnlyIndex ?? paramDetails.params.length;
7421
7417
  const varArgListParamIndex = paramDetails.argsIndex;
@@ -7534,6 +7530,9 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7534
7530
  argType.priv.tupleTypeArgs.length > 0) {
7535
7531
  tooManyPositionals = true;
7536
7532
  }
7533
+ else {
7534
+ unpackedArgOfUnknownLength = true;
7535
+ }
7537
7536
  }
7538
7537
  else {
7539
7538
  tooManyPositionals = true;
@@ -7563,6 +7562,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7563
7562
  let isArgCompatibleWithVariadic = false;
7564
7563
  const argTypeResult = getTypeOfArg(argList[argIndex], /* inferenceContext */ undefined);
7565
7564
  let listElementType;
7565
+ let enforceIterable = false;
7566
7566
  let advanceToNextArg = false;
7567
7567
  // Handle the case where *args is being passed to a function defined
7568
7568
  // with a ParamSpec and a Concatenate operator. PEP 612 indicates that
@@ -7622,8 +7622,12 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7622
7622
  listElementType = getTypeOfIterator({ type: argType, isIncomplete: argTypeResult.isIncomplete },
7623
7623
  /* isAsync */ false, errorNode,
7624
7624
  /* emitNotIterableError */ false)?.type;
7625
+ if (!listElementType) {
7626
+ enforceIterable = true;
7627
+ }
7628
+ unpackedArgOfUnknownLength = true;
7625
7629
  if (paramInfo.param.category === 1 /* ParamCategory.ArgsList */) {
7626
- matchedUnpackedListOfUnknownLength = true;
7630
+ unpackedArgMapsToVariadic = true;
7627
7631
  }
7628
7632
  if (isParamVariadic && listElementType) {
7629
7633
  isArgCompatibleWithVariadic = true;
@@ -7636,7 +7640,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7636
7640
  argCategory: 0 /* ArgCategory.Simple */,
7637
7641
  typeResult: { type: listElementType, isIncomplete: argTypeResult.isIncomplete },
7638
7642
  }
7639
- : { ...argList[argIndex] };
7643
+ : { ...argList[argIndex], enforceIterable };
7640
7644
  if (argTypeResult.isIncomplete) {
7641
7645
  isTypeIncomplete = true;
7642
7646
  }
@@ -7667,10 +7671,8 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7667
7671
  }
7668
7672
  trySetActive(argList[argIndex], paramDetails.params[paramIndex].param);
7669
7673
  // Note that the parameter has received an argument.
7670
- if (paramName &&
7671
- paramDetails.params[paramIndex].param.category === 0 /* ParamCategory.Simple */ &&
7672
- paramMap.has(paramName)) {
7673
- paramMap.get(paramName).argsReceived++;
7674
+ if (paramName && paramDetails.params[paramIndex].param.category === 0 /* ParamCategory.Simple */) {
7675
+ paramTracker.markArgReceived(paramInfo);
7674
7676
  }
7675
7677
  if (advanceToNextArg || paramDetails.params[paramIndex].param.category === 1 /* ParamCategory.ArgsList */) {
7676
7678
  argIndex++;
@@ -7739,9 +7741,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7739
7741
  });
7740
7742
  trySetActive(argList[argIndex], paramInfo.param);
7741
7743
  // Note that the parameter has received an argument.
7742
- if (paramName && paramMap.has(paramName) && paramInfo.kind !== parameterUtils_1.ParamKind.Positional) {
7743
- paramMap.get(paramName).argsReceived++;
7744
- }
7744
+ paramTracker.markArgReceived(paramInfo);
7745
7745
  argIndex++;
7746
7746
  paramIndex++;
7747
7747
  }
@@ -7815,7 +7815,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7815
7815
  const tdEntries = (0, typedDicts_1.getTypedDictMembersForClass)(evaluatorInterface, argType);
7816
7816
  const diag = new diagnostic_1.DiagnosticAddendum();
7817
7817
  tdEntries.knownItems.forEach((entry, name) => {
7818
- const paramEntry = paramMap.get(name);
7818
+ const paramEntry = paramTracker.lookupName(name);
7819
7819
  if (paramEntry) {
7820
7820
  if (paramEntry.argsReceived > 0) {
7821
7821
  diag.addMessage(localize_1.LocMessage.paramAlreadyAssigned().format({ name }));
@@ -7852,10 +7852,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7852
7852
  paramName: name,
7853
7853
  });
7854
7854
  // Remember that this parameter has already received a value.
7855
- paramMap.set(name, {
7856
- argsNeeded: 1,
7857
- argsReceived: 1,
7858
- });
7855
+ paramTracker.addKeywordParam(name, paramDetails.params[paramDetails.kwargsIndex]);
7859
7856
  }
7860
7857
  else {
7861
7858
  // If the function doesn't have a **kwargs parameter, we need to emit an error.
@@ -7941,6 +7938,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7941
7938
  unpackedDictArgType = types_1.UnknownType.create();
7942
7939
  }
7943
7940
  }
7941
+ unpackedArgOfUnknownLength = true;
7944
7942
  if (paramDetails.kwargsIndex !== undefined && unpackedDictArgType) {
7945
7943
  const paramType = paramDetails.params[paramDetails.kwargsIndex].type;
7946
7944
  validateArgTypeParams.push({
@@ -7952,6 +7950,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7952
7950
  errorNode: argList[argIndex].valueExpression || errorNode,
7953
7951
  paramName: paramDetails.params[paramDetails.kwargsIndex].param.name,
7954
7952
  });
7953
+ unpackedArgMapsToVariadic = true;
7955
7954
  }
7956
7955
  if (!isValidMappingType) {
7957
7956
  if (!canSkipDiagnosticForNode(errorNode) && !isTypeIncomplete) {
@@ -7972,7 +7971,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7972
7971
  const paramName = argList[argIndex].name;
7973
7972
  if (paramName) {
7974
7973
  const paramNameValue = paramName.d.value;
7975
- const paramEntry = paramMap.get(paramNameValue);
7974
+ const paramEntry = paramTracker.lookupName(paramNameValue);
7976
7975
  if (paramEntry) {
7977
7976
  if (paramEntry.argsReceived > 0) {
7978
7977
  if (!canSkipDiagnosticForNode(errorNode) && !isTypeIncomplete) {
@@ -8017,12 +8016,9 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
8017
8016
  errorNode: argList[argIndex].valueExpression ?? errorNode,
8018
8017
  paramName: paramNameValue,
8019
8018
  });
8020
- // Remember that this parameter has already received a value.
8021
- paramMap.set(paramNameValue, {
8022
- argsNeeded: 1,
8023
- argsReceived: 1,
8024
- });
8025
8019
  (0, debug_1.assert)(paramDetails.params[paramDetails.kwargsIndex], 'paramDetails.kwargsIndex params entry is undefined');
8020
+ // Remember that this parameter has already received a value.
8021
+ paramTracker.addKeywordParam(paramNameValue, paramDetails.params[paramDetails.kwargsIndex]);
8026
8022
  }
8027
8023
  trySetActive(argList[argIndex], paramDetails.params[paramDetails.kwargsIndex].param);
8028
8024
  }
@@ -8083,8 +8079,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
8083
8079
  if (paramIndex >= paramDetails.firstPositionOrKeywordIndex &&
8084
8080
  param.category === 0 /* ParamCategory.Simple */ &&
8085
8081
  param.name &&
8086
- paramMap.has(param.name) &&
8087
- paramMap.get(param.name).argsReceived === 0) {
8082
+ paramTracker.lookupDetails(paramInfo).argsReceived === 0) {
8088
8083
  const paramType = paramDetails.params[paramIndex].type;
8089
8084
  if (!unpackedDictKeyNames || unpackedDictKeyNames.includes(param.name)) {
8090
8085
  validateArgTypeParams.push({
@@ -8100,7 +8095,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
8100
8095
  paramName: param.name,
8101
8096
  isParamNameSynthesized: types_1.FunctionParam.isNameSynthesized(param),
8102
8097
  });
8103
- paramMap.get(param.name).argsReceived = 1;
8098
+ paramTracker.markArgReceived(paramDetails.params[paramIndex]);
8104
8099
  }
8105
8100
  }
8106
8101
  });
@@ -8110,10 +8105,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
8110
8105
  // (i.e. an arg starting with a "**"), we will assume that all parameters
8111
8106
  // are matched.
8112
8107
  if (!unpackedDictArgType && !types_1.FunctionType.isDefaultParamCheckDisabled(overload)) {
8113
- const unassignedParams = Array.from(paramMap.keys()).filter((name) => {
8114
- const entry = paramMap.get(name);
8115
- return !entry || entry.argsReceived < entry.argsNeeded;
8116
- });
8108
+ const unassignedParams = paramTracker.getUnassignedParams();
8117
8109
  if (unassignedParams.length > 0) {
8118
8110
  if (!canSkipDiagnosticForNode(errorNode)) {
8119
8111
  const missingParamNames = unassignedParams.map((p) => `"${p}"`).join(', ');
@@ -8133,8 +8125,8 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
8133
8125
  paramDetails.params.forEach((paramInfo) => {
8134
8126
  const param = paramInfo.param;
8135
8127
  if (param.category === 0 /* ParamCategory.Simple */ && param.name) {
8136
- const entry = paramMap.get(param.name);
8137
- if (entry && entry.argsNeeded === 0 && entry.argsReceived === 0) {
8128
+ const entry = paramTracker.lookupDetails(paramInfo);
8129
+ if (entry.argsNeeded === 0 && entry.argsReceived === 0) {
8138
8130
  const defaultArgType = paramInfo.defaultType;
8139
8131
  if (defaultArgType &&
8140
8132
  !(0, typeUtils_1.isEllipsisType)(defaultArgType) &&
@@ -8225,13 +8217,6 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
8225
8217
  }
8226
8218
  }
8227
8219
  }
8228
- let relevance = 0;
8229
- if (matchedUnpackedListOfUnknownLength) {
8230
- // Increase the relevance if we made assumptions about the length
8231
- // of an unpacked argument. This will favor overloads that
8232
- // associate this case with a *args parameter.
8233
- relevance++;
8234
- }
8235
8220
  // Special-case the builtin isinstance and issubclass functions.
8236
8221
  if (types_1.FunctionType.isBuiltIn(overload, ['isinstance', 'issubclass']) && validateArgTypeParams.length === 2) {
8237
8222
  validateArgTypeParams[1].isinstanceParam = true;
@@ -8245,7 +8230,8 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
8245
8230
  paramSpecTarget,
8246
8231
  paramSpecArgList,
8247
8232
  activeParam,
8248
- relevance,
8233
+ unpackedArgOfUnknownLength,
8234
+ unpackedArgMapsToVariadic,
8249
8235
  argumentMatchScore: 0,
8250
8236
  };
8251
8237
  }
@@ -8500,9 +8486,13 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
8500
8486
  }
8501
8487
  }
8502
8488
  // Calculate the return type.
8503
- let returnType = getEffectiveReturnType(type, {
8489
+ const returnTypeResult = getEffectiveReturnTypeResult(type, {
8504
8490
  callSiteInfo: { args: matchResults.argParams, errorNode },
8505
8491
  });
8492
+ let returnType = returnTypeResult.type;
8493
+ if (returnTypeResult.isIncomplete) {
8494
+ isTypeIncomplete = true;
8495
+ }
8506
8496
  if (condition.length > 0) {
8507
8497
  returnType = types_1.TypeBase.cloneForCondition(returnType, condition);
8508
8498
  }
@@ -8776,13 +8766,18 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
8776
8766
  : 16 /* EvalFlags.NoFinal */ | 2 /* EvalFlags.NoSpecialize */;
8777
8767
  const exprTypeResult = getTypeOfExpression(argParam.argument.valueExpression, flags, (0, typeUtils_1.makeInferenceContext)(expectedType, !!typeResult?.isIncomplete));
8778
8768
  argType = exprTypeResult.type;
8769
+ // If the argument is unpacked and we are supposed to enforce
8770
+ // that it's an iterator, do so now.
8771
+ if (argParam.argument.argCategory === 1 /* ArgCategory.UnpackedList */ && argParam.argument.enforceIterable) {
8772
+ const iteratorType = getTypeOfIterator(exprTypeResult,
8773
+ /* isAsync */ false, argParam.argument.valueExpression);
8774
+ // Try to prevent cascading errors if it was not iterable.
8775
+ argType = iteratorType?.type ?? types_1.UnknownType.create();
8776
+ }
8779
8777
  if (exprTypeResult.isIncomplete) {
8780
8778
  isTypeIncomplete = true;
8781
8779
  }
8782
- if (exprTypeResult.typeErrors) {
8783
- isCompatible = false;
8784
- }
8785
- else if (expectedType && (0, typeUtils_1.requiresSpecialization)(expectedType)) {
8780
+ if (expectedType && (0, typeUtils_1.requiresSpecialization)(expectedType)) {
8786
8781
  // Assign the argument type back to the expected type to assign
8787
8782
  // values to any unification variables.
8788
8783
  const clonedConstraints = constraints.clone();
@@ -10413,7 +10408,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
10413
10408
  : undefined, () => {
10414
10409
  const returnTypeResult = getTypeOfExpression(node.d.expr,
10415
10410
  /* flags */ undefined, (0, typeUtils_1.makeInferenceContext)(expectedReturnType));
10416
- functionType.priv.inferredReturnType = {
10411
+ functionType.shared.inferredReturnType = {
10417
10412
  type: returnTypeResult.type,
10418
10413
  };
10419
10414
  if (returnTypeResult.isIncomplete) {
@@ -13559,7 +13554,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
13559
13554
  awaitableFunctionType.shared.declaredReturnType = createAwaitableReturnType(node, functionType.shared.declaredReturnType, types_1.FunctionType.isGenerator(functionType));
13560
13555
  }
13561
13556
  else {
13562
- awaitableFunctionType.priv.inferredReturnType = {
13557
+ awaitableFunctionType.shared.inferredReturnType = {
13563
13558
  type: createAwaitableReturnType(node, getInferredReturnType(functionType), types_1.FunctionType.isGenerator(functionType)),
13564
13559
  };
13565
13560
  }
@@ -15737,11 +15732,11 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
15737
15732
  if (declaration.intrinsicType === 'int') {
15738
15733
  return { type: intType };
15739
15734
  }
15740
- if (declaration.intrinsicType === 'Iterable[str]') {
15741
- const iterableType = getBuiltInType(declaration.node, 'Iterable');
15742
- if ((0, types_1.isInstantiableClass)(iterableType)) {
15735
+ if (declaration.intrinsicType === 'MutableSequence[str]') {
15736
+ const sequenceType = getBuiltInType(declaration.node, 'MutableSequence');
15737
+ if ((0, types_1.isInstantiableClass)(sequenceType)) {
15743
15738
  return {
15744
- type: types_1.ClassType.cloneAsInstance(types_1.ClassType.specialize(iterableType, [strType])),
15739
+ type: types_1.ClassType.cloneAsInstance(types_1.ClassType.specialize(sequenceType, [strType])),
15745
15740
  };
15746
15741
  }
15747
15742
  }
@@ -16014,18 +16009,30 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
16014
16009
  }
16015
16010
  if (loaderActions.implicitImports) {
16016
16011
  loaderActions.implicitImports.forEach((implicitImport, name) => {
16012
+ const existingLoaderField = moduleType.priv.loaderFields.get(name);
16017
16013
  // Recursively apply loader actions.
16018
16014
  let symbolType;
16019
16015
  if (implicitImport.isUnresolved) {
16020
16016
  symbolType = types_1.UnknownType.create();
16021
16017
  }
16022
16018
  else {
16023
- const moduleName = moduleType.priv.moduleName ? moduleType.priv.moduleName + '.' + name : '';
16024
- const importedModuleType = types_1.ModuleType.create(moduleName, implicitImport.uri);
16019
+ let importedModuleType;
16020
+ const existingType = existingLoaderField?.getSynthesizedType();
16021
+ if (existingType?.type && (0, types_1.isModule)(existingType.type)) {
16022
+ importedModuleType = existingType.type;
16023
+ }
16024
+ else {
16025
+ const moduleName = moduleType.priv.moduleName
16026
+ ? moduleType.priv.moduleName + '.' + name
16027
+ : '';
16028
+ importedModuleType = types_1.ModuleType.create(moduleName, implicitImport.uri);
16029
+ }
16025
16030
  symbolType = applyLoaderActionsToModuleType(importedModuleType, implicitImport, importLookup);
16026
16031
  }
16027
- const importedModuleSymbol = symbol_1.Symbol.createWithType(0 /* SymbolFlags.None */, symbolType);
16028
- moduleType.priv.loaderFields.set(name, importedModuleSymbol);
16032
+ if (!existingLoaderField) {
16033
+ const importedModuleSymbol = symbol_1.Symbol.createWithType(0 /* SymbolFlags.None */, symbolType);
16034
+ moduleType.priv.loaderFields.set(name, importedModuleSymbol);
16035
+ }
16029
16036
  });
16030
16037
  }
16031
16038
  return moduleType;
@@ -16034,15 +16041,28 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
16034
16041
  // is pointing at a module, and we need to synthesize a
16035
16042
  // module type.
16036
16043
  if (resolvedDecl.type === 8 /* DeclarationType.Alias */) {
16037
- // Build a module type that corresponds to the declaration and
16038
- // its associated loader actions.
16039
- const moduleType = types_1.ModuleType.create(resolvedDecl.moduleName, resolvedDecl.uri);
16040
- if (resolvedDecl.symbolName && resolvedDecl.submoduleFallback) {
16041
- return applyLoaderActionsToModuleType(moduleType, resolvedDecl.submoduleFallback, importLookup);
16044
+ let moduleType;
16045
+ // See if this is an import that shares a ModuleType with another
16046
+ // import statement. If so, used the cached type. This happens when
16047
+ // multiple import statements start with the same module name, such
16048
+ // as "import a.b" and "import a.c".
16049
+ if (resolvedDecl.node.nodeType === 24 /* ParseNodeType.ImportAs */) {
16050
+ const cachedType = readTypeCache(resolvedDecl.node.d.module, 0 /* EvalFlags.None */);
16051
+ if (cachedType && (0, types_1.isModule)(cachedType)) {
16052
+ moduleType = cachedType;
16053
+ }
16042
16054
  }
16043
- else {
16044
- return applyLoaderActionsToModuleType(moduleType, resolvedDecl, importLookup);
16055
+ if (!moduleType) {
16056
+ // Build a module type that corresponds to the declaration and
16057
+ // its associated loader actions.
16058
+ moduleType = types_1.ModuleType.create(resolvedDecl.moduleName, resolvedDecl.uri);
16059
+ if (resolvedDecl.node.nodeType === 24 /* ParseNodeType.ImportAs */) {
16060
+ writeTypeCache(resolvedDecl.node.d.module, { type: moduleType }, 0 /* EvalFlags.None */);
16061
+ }
16045
16062
  }
16063
+ return applyLoaderActionsToModuleType(moduleType, resolvedDecl.symbolName && resolvedDecl.submoduleFallback
16064
+ ? resolvedDecl.submoduleFallback
16065
+ : resolvedDecl, importLookup);
16046
16066
  }
16047
16067
  const declaredType = getTypeForDeclaration(resolvedDecl);
16048
16068
  if (declaredType.type) {
@@ -16598,38 +16618,49 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
16598
16618
  }
16599
16619
  }
16600
16620
  }
16621
+ function getEffectiveReturnType(type) {
16622
+ return getEffectiveReturnTypeResult(type).type;
16623
+ }
16624
+ function getInferredReturnType(type) {
16625
+ return getInferredReturnTypeResult(type).type;
16626
+ }
16601
16627
  // Returns the return type of the function. If the type is explicitly provided in
16602
16628
  // a type annotation, that type is returned. If not, an attempt is made to infer
16603
16629
  // the return type. If a list of args is provided, the inference logic may take
16604
16630
  // into account argument types to infer the return type.
16605
- function getEffectiveReturnType(type, options) {
16631
+ function getEffectiveReturnTypeResult(type, options) {
16606
16632
  const specializedReturnType = types_1.FunctionType.getEffectiveReturnType(type, /* includeInferred */ false);
16607
16633
  if (specializedReturnType && !(0, types_1.isUnknown)(specializedReturnType)) {
16608
- return specializedReturnType;
16634
+ return { type: specializedReturnType };
16609
16635
  }
16610
- return getInferredReturnType(type, options?.callSiteInfo);
16636
+ return getInferredReturnTypeResult(type, options?.callSiteInfo);
16611
16637
  }
16612
- function _getInferredReturnType(type, callSiteInfo) {
16638
+ function _getInferredReturnTypeResult(type, callSiteInfo) {
16613
16639
  let returnType;
16614
16640
  let isIncomplete = false;
16615
16641
  const analyzeUnannotatedFunctions = true;
16616
16642
  // Don't attempt to infer the return type for a stub file.
16617
16643
  if (types_1.FunctionType.isStubDefinition(type)) {
16618
- return types_1.UnknownType.create();
16644
+ return { type: types_1.UnknownType.create() };
16619
16645
  }
16620
16646
  // Don't infer the return type for a ParamSpec value.
16621
16647
  if (types_1.FunctionType.isParamSpecValue(type)) {
16622
- return types_1.UnknownType.create();
16648
+ return { type: types_1.UnknownType.create() };
16623
16649
  }
16624
16650
  // Don't infer the return type for an overloaded function (unless it's synthesized,
16625
16651
  // which is needed for proper operation of the __get__ method in properties).
16626
16652
  if (types_1.FunctionType.isOverloaded(type) && !types_1.FunctionType.isSynthesizedMethod(type)) {
16627
- return types_1.UnknownType.create();
16653
+ return { type: types_1.UnknownType.create() };
16628
16654
  }
16655
+ const evalCount = type.shared.inferredReturnType?.evaluationCount ?? 0;
16629
16656
  // If the return type has already been lazily evaluated,
16630
16657
  // don't bother computing it again.
16631
- if (type.priv.inferredReturnType && !type.priv.inferredReturnType.isIncomplete) {
16632
- returnType = type.priv.inferredReturnType.type;
16658
+ if (type.shared.inferredReturnType && !type.shared.inferredReturnType.isIncomplete) {
16659
+ returnType = type.shared.inferredReturnType.type;
16660
+ }
16661
+ else if (evalCount > maxReturnTypeInferenceAttempts) {
16662
+ // Detect a case where a return type won't converge because of recursion.
16663
+ returnType = types_1.UnknownType.create();
16633
16664
  }
16634
16665
  else {
16635
16666
  // Don't bother inferring the return type of __init__ because it's
@@ -16676,7 +16707,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
16676
16707
  }
16677
16708
  returnType = (0, typeUtils_1.makeTypeVarsFree)(returnType, typeVarScopes);
16678
16709
  // Cache the type for next time.
16679
- type.priv.inferredReturnType = { type: returnType, isIncomplete };
16710
+ type.shared.inferredReturnType = { type: returnType, isIncomplete, evaluationCount: evalCount + 1 };
16680
16711
  }
16681
16712
  // If the type is partially unknown and the function has one or more unannotated
16682
16713
  // params, try to analyze the function with the provided argument types and
@@ -16713,7 +16744,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
16713
16744
  }
16714
16745
  }
16715
16746
  }
16716
- return returnType;
16747
+ return { type: returnType, isIncomplete };
16717
16748
  }
16718
16749
  function inferReturnTypeForCallSite(type, callSiteInfo) {
16719
16750
  const args = callSiteInfo.args;
@@ -18243,8 +18274,10 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
18243
18274
  }
18244
18275
  // Determines whether the two types are potentially comparable -- i.e.
18245
18276
  // their types overlap in such a way that it makes sense for them to
18246
- // be compared with an == or != operator.
18247
- function isTypeComparable(leftType, rightType) {
18277
+ // be compared with an == or != operator. The functional also supports
18278
+ // a special variant that can be used for the "is" and "is not" operator.
18279
+ // This variant can be less conservative in some cases.
18280
+ function isTypeComparable(leftType, rightType, assumeIsOperator = false) {
18248
18281
  if ((0, types_1.isAnyOrUnknown)(leftType) || (0, types_1.isAnyOrUnknown)(rightType)) {
18249
18282
  return true;
18250
18283
  }
@@ -18284,6 +18317,16 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
18284
18317
  if (assignType(genericLeftType, genericRightType) || assignType(genericRightType, genericLeftType)) {
18285
18318
  return true;
18286
18319
  }
18320
+ // Check for the "is None" or "is not None" case.
18321
+ if (assumeIsOperator && (0, typeUtils_1.isNoneInstance)(rightType)) {
18322
+ if ((0, typeUtils_1.isNoneInstance)(leftType)) {
18323
+ return true;
18324
+ }
18325
+ // The LHS could be a protocol or 'object', in which case None is
18326
+ // potentially comparable to it. In other cases, None is not comparable
18327
+ // because the types are disjoint.
18328
+ return assignType(leftType, rightType);
18329
+ }
18287
18330
  // Assume that if the types are disjoint and built-in classes that they
18288
18331
  // will never be comparable.
18289
18332
  if (types_1.ClassType.isBuiltIn(leftType) && types_1.ClassType.isBuiltIn(rightType) && types_1.TypeBase.isInstance(rightType)) {
@@ -19197,72 +19240,9 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
19197
19240
  }
19198
19241
  return canAssign;
19199
19242
  }
19200
- // If the declaredType contains type arguments that are "Any" and
19201
- // the corresponding type argument in the assignedType is not "Any",
19202
- // replace that type argument in the assigned type. This function assumes
19203
- // that the caller has already verified that the assignedType is assignable
19204
- // to the declaredType.
19205
- function replaceTypeArgsWithAny(node, declaredType, assignedType, recursionCount = 0) {
19206
- if (recursionCount > types_1.maxTypeRecursionCount) {
19207
- return undefined;
19208
- }
19209
- recursionCount++;
19210
- if (assignedType.shared.typeParams.length > 0 &&
19211
- assignedType.priv.typeArgs &&
19212
- assignedType.priv.typeArgs.length <= assignedType.shared.typeParams.length &&
19213
- !assignedType.priv.tupleTypeArgs) {
19214
- const constraints = new constraintTracker_1.ConstraintTracker();
19215
- (0, constraintSolver_1.addConstraintsForExpectedType)(evaluatorInterface, types_1.ClassType.specialize(assignedType, /* typeArgs */ undefined), declaredType, constraints, ParseTreeUtils.getTypeVarScopesForNode(node), node.start);
19216
- let replacedTypeArg = false;
19217
- const solution = (0, constraintSolver_1.solveConstraints)(evaluatorInterface, constraints).getMainSolutionSet();
19218
- const newTypeArgs = assignedType.priv.typeArgs.map((typeArg, index) => {
19219
- const typeParam = assignedType.shared.typeParams[index];
19220
- const expectedTypeArgType = solution.getType(typeParam);
19221
- if (expectedTypeArgType) {
19222
- if ((0, types_1.isAnyOrUnknown)(expectedTypeArgType) || (0, types_1.isAnyOrUnknown)(typeArg)) {
19223
- replacedTypeArg = true;
19224
- return expectedTypeArgType;
19225
- }
19226
- if ((0, types_1.isClassInstance)(expectedTypeArgType) && (0, types_1.isClassInstance)(typeArg)) {
19227
- // Recursively replace Any in the type argument.
19228
- const recursiveReplacement = replaceTypeArgsWithAny(node, expectedTypeArgType, typeArg, recursionCount);
19229
- if (recursiveReplacement) {
19230
- replacedTypeArg = true;
19231
- return recursiveReplacement;
19232
- }
19233
- }
19234
- else if ((0, typeUtils_1.containsAnyRecursive)(expectedTypeArgType)) {
19235
- // If the expected type arg contains an Any, we can replace it with
19236
- // a version that doesn't contain Any if the replacement doesn't violate
19237
- // the variance of the type parameter.
19238
- const variance = types_1.TypeVarType.getVariance(typeParam);
19239
- const isSubtype = assignType(expectedTypeArgType, typeArg);
19240
- const isSupertype = assignType(typeArg, expectedTypeArgType);
19241
- if ((variance === 4 /* Variance.Contravariant */ || isSubtype) &&
19242
- (variance === 3 /* Variance.Covariant */ || isSupertype)) {
19243
- replacedTypeArg = true;
19244
- return expectedTypeArgType;
19245
- }
19246
- }
19247
- }
19248
- return typeArg;
19249
- });
19250
- if (replacedTypeArg) {
19251
- return types_1.ClassType.specialize(assignedType, newTypeArgs);
19252
- }
19253
- }
19254
- // If the declared and assigned types are the same generic type but the assigned type
19255
- // contains one or more unknowns, use the declared type instead.
19256
- if (types_1.ClassType.isSameGenericClass(declaredType, assignedType)) {
19257
- if ((0, typeUtils_1.containsAnyRecursive)(assignedType) && !(0, typeUtils_1.containsAnyRecursive)(declaredType)) {
19258
- return declaredType;
19259
- }
19260
- }
19261
- return undefined;
19262
- }
19263
19243
  // When a value is assigned to a variable with a declared type,
19264
19244
  // we may be able to narrow the type based on the assignment.
19265
- function narrowTypeBasedOnAssignment(node, declaredType, assignedTypeResult) {
19245
+ function narrowTypeBasedOnAssignment(declaredType, assignedTypeResult) {
19266
19246
  // TODO: The rules for narrowing types on assignment are not defined in
19267
19247
  // the typing spec. Pyright's current logic is currently not even internally
19268
19248
  // consistent and probably not sound from a type theory perspective. It
@@ -19278,46 +19258,36 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
19278
19258
  }
19279
19259
  }
19280
19260
  const narrowedSubtype = (0, typeUtils_1.mapSubtypes)(declaredType, (declaredSubtype) => {
19281
- // We can't narrow "Any".
19282
- if ((0, types_1.isAnyOrUnknown)(declaredSubtype)) {
19283
- return declaredSubtype;
19261
+ if (!assignType(declaredSubtype, assignedSubtype)) {
19262
+ return undefined;
19284
19263
  }
19285
- if (assignType(declaredSubtype, assignedSubtype)) {
19286
- // If the assigned subtype is Any, stick with the declared type.
19287
- if ((0, types_1.isAny)(assignedSubtype)) {
19288
- return declaredSubtype;
19289
- }
19290
- if ((0, types_1.isClass)(declaredSubtype) &&
19291
- (0, types_1.isClass)(assignedSubtype) &&
19292
- types_1.TypeBase.isInstance(declaredSubtype) === types_1.TypeBase.isInstance(assignedSubtype)) {
19293
- const result = replaceTypeArgsWithAny(node, declaredSubtype, assignedSubtype);
19294
- if (result) {
19295
- assignedSubtype = result;
19296
- }
19264
+ // Retain unknowns for code flow analysis convergence and for
19265
+ // unknown type reporting in strict mode.
19266
+ if ((0, types_1.isUnknown)(assignedSubtype)) {
19267
+ return assignedSubtype;
19268
+ }
19269
+ // If the two types are bidirectionally assignable, they are
19270
+ // either equivalent (in which case it doesn't matter which
19271
+ // one we choose) or one or both include gradual types (Any, etc.),
19272
+ // in which case we'll want to stick with the declared subtype.
19273
+ if (assignType(assignedSubtype, declaredSubtype)) {
19274
+ // We need to be careful with TypedDict types that have
19275
+ // narrowed fields. In this case, we want to return the
19276
+ // assigned type.
19277
+ if ((0, types_1.isClass)(assignedSubtype) &&
19278
+ assignedSubtype.priv.typedDictNarrowedEntries &&
19279
+ (0, types_1.isTypeSame)(assignedSubtype, declaredSubtype, { ignoreTypedDictNarrowEntries: true })) {
19297
19280
  return assignedSubtype;
19298
19281
  }
19299
- if (!(0, types_1.isTypeVar)(declaredSubtype) &&
19300
- (0, types_1.isTypeVar)(assignedSubtype) &&
19301
- !types_1.TypeVarType.isBound(assignedSubtype)) {
19302
- // If the source is an unsolved TypeVar but the declared type is concrete,
19303
- // use the concrete type.
19304
- return declaredSubtype;
19305
- }
19306
- // If the declared type doesn't contain any `Any` but the assigned
19307
- // type does, stick with the declared type. We don't include unknowns
19308
- // in the assigned subtype check here so unknowns are preserved so
19309
- // reportUnknownVariableType assignment diagnostics are reported.
19310
- // TODO - this is an inconsistency because Any and Unknown should
19311
- // always be treated the same for purposes of type narrowing. This
19312
- // should be revisited once the narrowing-on-assignment behavior
19313
- // is properly specified in the typing spec.
19314
- if ((0, typeUtils_1.containsAnyRecursive)(assignedSubtype, /* includeUnknown */ false) &&
19315
- !(0, typeUtils_1.containsAnyRecursive)(declaredSubtype)) {
19316
- return declaredSubtype;
19282
+ // We also need to be careful with callback protocols.
19283
+ if ((0, types_1.isClassInstance)(declaredSubtype) && types_1.ClassType.isProtocolClass(declaredSubtype)) {
19284
+ if ((0, types_1.isFunction)(assignedSubtype) || (0, types_1.isOverloaded)(assignedSubtype)) {
19285
+ return assignedSubtype;
19286
+ }
19317
19287
  }
19318
- return assignedSubtype;
19288
+ return declaredSubtype;
19319
19289
  }
19320
- return undefined;
19290
+ return assignedSubtype;
19321
19291
  });
19322
19292
  // If we couldn't assign the assigned subtype any of the declared
19323
19293
  // subtypes, the types are incompatible. Return the unnarrowed form.
@@ -19332,12 +19302,12 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
19332
19302
  // with the declared type. In strict mode, this will retain the "unknown type"
19333
19303
  // diagnostics while still providing reasonable completion suggestions.
19334
19304
  if ((0, typeUtils_1.isIncompleteUnknown)(narrowedType)) {
19335
- return { type: narrowedType };
19305
+ return { type: narrowedType, isIncomplete: assignedTypeResult.isIncomplete };
19336
19306
  }
19337
19307
  else if ((0, types_1.isUnknown)(narrowedType)) {
19338
- return { type: (0, types_1.combineTypes)([narrowedType, declaredType]) };
19308
+ return { type: (0, types_1.combineTypes)([narrowedType, declaredType]), isIncomplete: assignedTypeResult.isIncomplete };
19339
19309
  }
19340
- return { type: narrowedType };
19310
+ return { type: narrowedType, isIncomplete: assignedTypeResult.isIncomplete };
19341
19311
  }
19342
19312
  function validateOverrideMethod(baseMethod, overrideMethod, baseClass, diag, enforceParamNames = true) {
19343
19313
  // If we're overriding a non-method with a method, report it as an error.
@@ -19860,6 +19830,11 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
19860
19830
  if (!baseType) {
19861
19831
  return types_1.FunctionType.clone(functionType, /* stripFirstParam */ true);
19862
19832
  }
19833
+ // If the first parameter was already stripped, it has already been
19834
+ // bound. Don't attempt to rebind.
19835
+ if (functionType.priv.strippedFirstParamType) {
19836
+ return functionType;
19837
+ }
19863
19838
  if (types_1.FunctionType.isInstanceMethod(functionType)) {
19864
19839
  // If the baseType is a metaclass, don't specialize the function.
19865
19840
  if ((0, typeUtils_1.isInstantiableMetaclass)(baseType)) {
@@ -19917,6 +19892,22 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
19917
19892
  }
19918
19893
  else {
19919
19894
  const subDiag = diag?.createAddendum();
19895
+ // Protect against the case where a callback protocol is being
19896
+ // bound to its own __call__ method but the first parameter
19897
+ // is annotated with its own callable type. This can lead to
19898
+ // infinite recursion.
19899
+ if ((0, types_1.isFunction)(memberTypeFirstParamType) || (0, types_1.isOverloaded)(memberTypeFirstParamType)) {
19900
+ if ((0, types_1.isClassInstance)(firstParamType) && types_1.ClassType.isProtocolClass(firstParamType)) {
19901
+ if (subDiag) {
19902
+ subDiag.addMessage(localize_1.LocMessage.bindTypeMismatch().format({
19903
+ type: printType(firstParamType),
19904
+ methodName: memberType.shared.name || '<anonymous>',
19905
+ paramName: memberTypeFirstParam.name || '__p0',
19906
+ }));
19907
+ }
19908
+ return undefined;
19909
+ }
19910
+ }
19920
19911
  if (!assignType(memberTypeFirstParamType, firstParamType, subDiag?.createAddendum(), constraints, 8192 /* AssignTypeFlags.AllowUnspecifiedTypeArgs */, recursionCount)) {
19921
19912
  if (memberTypeFirstParam.name &&
19922
19913
  !types_1.FunctionParam.isNameSynthesized(memberTypeFirstParam) &&
@@ -20195,7 +20186,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
20195
20186
  return codeFlowEngine.printControlFlowGraph(flowNode, reference, callName, logger);
20196
20187
  }
20197
20188
  // Track these apis internal usages when logging is on. otherwise, it should be noop.
20198
- const getInferredReturnType = wrapWithLogger(_getInferredReturnType);
20189
+ const getInferredReturnTypeResult = wrapWithLogger(_getInferredReturnTypeResult);
20199
20190
  const evaluatorInterface = {
20200
20191
  runWithCancellationToken,
20201
20192
  getType,