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

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 (69) hide show
  1. package/dist/analyzer/binder.js +8 -0
  2. package/dist/analyzer/binder.js.map +1 -1
  3. package/dist/analyzer/checker.js +4 -3
  4. package/dist/analyzer/checker.js.map +1 -1
  5. package/dist/analyzer/codeFlowEngine.js +73 -27
  6. package/dist/analyzer/codeFlowEngine.js.map +1 -1
  7. package/dist/analyzer/overloadResultAdmission.js +115 -3
  8. package/dist/analyzer/overloadResultAdmission.js.map +1 -1
  9. package/dist/analyzer/overloadResultController.js +36 -10
  10. package/dist/analyzer/overloadResultController.js.map +1 -1
  11. package/dist/analyzer/overloadResultSelector.js +32 -12
  12. package/dist/analyzer/overloadResultSelector.js.map +1 -1
  13. package/dist/analyzer/parseTreeUtils.d.ts +1 -0
  14. package/dist/analyzer/parseTreeUtils.js +13 -0
  15. package/dist/analyzer/parseTreeUtils.js.map +1 -1
  16. package/dist/analyzer/patternMatching.js +64 -26
  17. package/dist/analyzer/patternMatching.js.map +1 -1
  18. package/dist/analyzer/program.d.ts +3 -0
  19. package/dist/analyzer/program.js +34 -9
  20. package/dist/analyzer/program.js.map +1 -1
  21. package/dist/analyzer/service.js +6 -2
  22. package/dist/analyzer/service.js.map +1 -1
  23. package/dist/analyzer/sourceEnumerator.d.ts +3 -1
  24. package/dist/analyzer/sourceEnumerator.js +30 -11
  25. package/dist/analyzer/sourceEnumerator.js.map +1 -1
  26. package/dist/analyzer/sourceMapper.d.ts +1 -0
  27. package/dist/analyzer/sourceMapper.js +10 -4
  28. package/dist/analyzer/sourceMapper.js.map +1 -1
  29. package/dist/analyzer/tuples.js +17 -6
  30. package/dist/analyzer/tuples.js.map +1 -1
  31. package/dist/analyzer/typeEvaluator.js +276 -43
  32. package/dist/analyzer/typeEvaluator.js.map +1 -1
  33. package/dist/analyzer/typeGuards.d.ts +5 -1
  34. package/dist/analyzer/typeGuards.js +116 -31
  35. package/dist/analyzer/typeGuards.js.map +1 -1
  36. package/dist/analyzer/typeStubRenderer.d.ts +6 -1
  37. package/dist/analyzer/typeStubRenderer.js +19 -12
  38. package/dist/analyzer/typeStubRenderer.js.map +1 -1
  39. package/dist/analyzer/typedDicts.d.ts +2 -1
  40. package/dist/analyzer/typedDicts.js +49 -10
  41. package/dist/analyzer/typedDicts.js.map +1 -1
  42. package/dist/common/configOptions.d.ts +1 -0
  43. package/dist/common/configOptions.js +9 -0
  44. package/dist/common/configOptions.js.map +1 -1
  45. package/dist/common/windowsProcessTree.json +252 -33
  46. package/dist/tests/checker.test.js +50 -0
  47. package/dist/tests/checker.test.js.map +1 -1
  48. package/dist/tests/config.test.js +126 -0
  49. package/dist/tests/config.test.js.map +1 -1
  50. package/dist/tests/fourslash/hover.typedDict.get.fourslash.js +11 -0
  51. package/dist/tests/fourslash/hover.typedDict.get.fourslash.js.map +1 -1
  52. package/dist/tests/overloadResultController.test.js +379 -1
  53. package/dist/tests/overloadResultController.test.js.map +1 -1
  54. package/dist/tests/signatureHelp.test.js +34 -0
  55. package/dist/tests/signatureHelp.test.js.map +1 -1
  56. package/dist/tests/sourceEnumeratorSymlink.test.js +98 -13
  57. package/dist/tests/sourceEnumeratorSymlink.test.js.map +1 -1
  58. package/dist/tests/sourceMapperUtils.test.js +143 -0
  59. package/dist/tests/sourceMapperUtils.test.js.map +1 -1
  60. package/dist/tests/typeEvaluator1.test.js +19 -2
  61. package/dist/tests/typeEvaluator1.test.js.map +1 -1
  62. package/dist/tests/typeEvaluator5.test.js +1 -1
  63. package/dist/tests/typeEvaluator6.test.js +20 -0
  64. package/dist/tests/typeEvaluator6.test.js.map +1 -1
  65. package/dist/tests/typeEvaluator7.test.js +10 -0
  66. package/dist/tests/typeEvaluator7.test.js.map +1 -1
  67. package/dist/tests/typeEvaluator8.test.js +2 -1
  68. package/dist/tests/typeEvaluator8.test.js.map +1 -1
  69. package/package.json +3 -3
@@ -80,6 +80,7 @@ const namedTuples_1 = require("./namedTuples");
80
80
  const operations_1 = require("./operations");
81
81
  const parameterUtils_1 = require("./parameterUtils");
82
82
  const ParseTreeUtils = __importStar(require("./parseTreeUtils"));
83
+ const parseTreeWalker_1 = require("./parseTreeWalker");
83
84
  const patternMatching_1 = require("./patternMatching");
84
85
  const properties_1 = require("./properties");
85
86
  const protocols_1 = require("./protocols");
@@ -203,6 +204,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
203
204
  let functionRecursionMap = new Map();
204
205
  let codeFlowAnalyzerCache = new Map();
205
206
  let typeCache = new Map();
207
+ let contextualLambdaTypeCache;
206
208
  let typeFormTypeCache = new Map();
207
209
  let effectiveTypeCache = new Map();
208
210
  let exceptionTargetSymbolCache = new Map();
@@ -399,6 +401,55 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
399
401
  function setTypeResultForNode(node, typeResult, flags = 0 /* EvalFlags.None */) {
400
402
  writeTypeCache(node, typeResult, flags);
401
403
  }
404
+ function captureContextualLambdaTypes(node, typeResult) {
405
+ const cache = contextualLambdaTypeCache;
406
+ if (!cache || !cache.lambdaNodes.some((root) => ParseTreeUtils.isNodeContainedWithin(node, root))) {
407
+ return;
408
+ }
409
+ captureLambdaTypeCacheEntries(node, cache, typeResult);
410
+ }
411
+ function captureLambdaTypeCacheEntries(node, cache, typeResult) {
412
+ checkForCancellation();
413
+ const entry = typeResult ? { typeResult, flags: 0 /* EvalFlags.None */, incompleteGenCount } : readTypeCacheEntry(node);
414
+ if (entry && !entry.typeResult.isIncomplete) {
415
+ captureLambdaTypeCacheEntry(node, cache, entry);
416
+ }
417
+ if (typeResult) {
418
+ return;
419
+ }
420
+ for (const child of (0, parseTreeWalker_1.getChildNodes)(node)) {
421
+ // Nested lambdas capture their own contextual types before any
422
+ // non-contextual fallback can replace them.
423
+ if (child && child.nodeType !== 33 /* ParseNodeType.Lambda */) {
424
+ captureLambdaTypeCacheEntries(child, cache);
425
+ }
426
+ }
427
+ }
428
+ function captureLambdaTypeCacheEntry(node, cache, entry) {
429
+ const nodeEntries = cache.entries.get(node) ?? new Map();
430
+ // Generic inference can revisit a lambda within the same callable branch.
431
+ nodeEntries.set(cache.branchIndex, entry);
432
+ cache.entries.set(node, nodeEntries);
433
+ }
434
+ function combineContextualLambdaTypes(cache) {
435
+ for (const [node, branchEntries] of cache.entries) {
436
+ checkForCancellation();
437
+ const nodeEntries = Array.from(branchEntries.values());
438
+ const lastEntry = nodeEntries[nodeEntries.length - 1];
439
+ writeTypeCache(node, {
440
+ ...lastEntry.typeResult,
441
+ type: (0, types_1.combineTypes)(nodeEntries.map((entry) => entry.typeResult.type)),
442
+ typeErrors: nodeEntries.some((entry) => entry.typeResult.typeErrors),
443
+ }, readTypeCacheEntry(node)?.flags ?? lastEntry.flags);
444
+ const parentCache = contextualLambdaTypeCache;
445
+ const combinedEntry = readTypeCacheEntry(node);
446
+ if (parentCache &&
447
+ combinedEntry &&
448
+ parentCache.lambdaNodes.some((root) => ParseTreeUtils.isNodeContainedWithin(node, root))) {
449
+ captureLambdaTypeCacheEntry(node, parentCache, combinedEntry);
450
+ }
451
+ }
452
+ }
402
453
  function getMaxCodeComplexity() {
403
454
  return maxCodeComplexity;
404
455
  }
@@ -6100,12 +6151,22 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
6100
6151
  }
6101
6152
  }
6102
6153
  }
6103
- else if ((0, types_1.isClassInstance)(valueType) && types_1.ClassType.isBuiltIn(valueType, 'slice')) {
6154
+ else if (usage.method === 'get' &&
6155
+ index0Expr.nodeType === 46 /* ParseNodeType.Slice */ &&
6156
+ (0, types_1.isClassInstance)(valueType) &&
6157
+ types_1.ClassType.isBuiltIn(valueType, 'slice')) {
6104
6158
  const tupleType = (0, typeUtils_1.getSpecializedTupleType)(baseType);
6105
- if (tupleType && index0Expr.nodeType === 46 /* ParseNodeType.Slice */) {
6106
- const slicedTupleType = (0, tuples_1.getSlicedTupleType)(evaluatorInterface, tupleType, index0Expr);
6107
- if (slicedTupleType) {
6108
- return { type: slicedTupleType };
6159
+ if (tupleType) {
6160
+ // Skip this if a subclass overrides the tuple's __getitem__ method.
6161
+ const getItemMember = (0, typeUtils_1.lookUpObjectMember)(baseType, '__getitem__', 16 /* MemberAccessFlags.SkipInstanceMembers */);
6162
+ const isTupleGetItem = !getItemMember ||
6163
+ ((0, types_1.isInstantiableClass)(getItemMember.classType) &&
6164
+ types_1.ClassType.isBuiltIn(getItemMember.classType, 'tuple'));
6165
+ if (isTupleGetItem) {
6166
+ const slicedTupleType = (0, tuples_1.getSlicedTupleType)(evaluatorInterface, tupleType, index0Expr);
6167
+ if (slicedTupleType) {
6168
+ return { type: slicedTupleType };
6169
+ }
6109
6170
  }
6110
6171
  }
6111
6172
  }
@@ -7218,7 +7279,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7218
7279
  // there will be only one argument list in expandedArgTypes, and all entries
7219
7280
  // (one for each argument) will be undefined. On subsequent calls, this
7220
7281
  // list will grow to include union expansions.
7221
- function validateOverloadsWithExpandedTypes(errorNode, expandedArgTypes, argParamMatches, constraints, skipUnknownArgCheck, inferenceContext) {
7282
+ function validateOverloadsWithExpandedTypes(errorNode, expandedArgTypes, argParamMatches, constraints, skipUnknownArgCheck, inferenceContext, skipFinalValidation = false) {
7222
7283
  const returnTypes = [];
7223
7284
  const specializedInitSelfTypes = [];
7224
7285
  let matchedOverloads = [];
@@ -7261,17 +7322,14 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7261
7322
  if (!callResult.argumentErrors && callResult.returnType) {
7262
7323
  if (evaluatorOptions.experimentalOverloadResult &&
7263
7324
  !callResult.isTypeIncomplete &&
7264
- !overload.priv.boundToType &&
7265
- !overload.shared.methodClass &&
7266
- !overload.shared.declaration?.isMethod &&
7267
7325
  errorNode.nodeType === 9 /* ParseNodeType.Call */ &&
7268
- errorNode.d.leftExpr.nodeType === 38 /* ParseNodeType.Name */ &&
7269
- errorNode.parent?.nodeType === 3 /* ParseNodeType.Assignment */ &&
7270
- errorNode.parent.d.rightExpr === errorNode &&
7326
+ (0, overloadResultSelector_1.isAutomaticOverloadSeedSyntax)(errorNode) &&
7271
7327
  expandedArgTypes.length === 1 &&
7272
- !hasArgTypeOverride &&
7273
- callResult.argResults) {
7274
- evaluatorOptions.experimentalOverloadResult.considerActivation(errorNode, callResult.argResults);
7328
+ !hasArgTypeOverride) {
7329
+ const receiver = overload.priv.boundToType;
7330
+ evaluatorOptions.experimentalOverloadResult.considerActivation(errorNode, receiver && (0, types_1.isClassInstance)(receiver)
7331
+ ? [{ argType: receiver }, ...(callResult.argResults ?? [])]
7332
+ : callResult.argResults ?? []);
7275
7333
  }
7276
7334
  overloadsUsedForCall.push(overload);
7277
7335
  matchedOverload = overload;
@@ -7390,6 +7448,16 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7390
7448
  if (constraints && isDefinitiveMatchFound) {
7391
7449
  constraints.copyFromClone(matchedOverloads[matchedOverloads.length - 1].constraints);
7392
7450
  }
7451
+ // A speculative refinement does not need to populate the type cache;
7452
+ // the original call has already performed the normal final validation.
7453
+ if (skipFinalValidation) {
7454
+ return {
7455
+ argumentErrors: false,
7456
+ returnType: (0, types_1.combineTypes)(returnTypes),
7457
+ isTypeIncomplete,
7458
+ overloadsUsedForCall,
7459
+ };
7460
+ }
7393
7461
  // And run through the first expanded argument list one more time to
7394
7462
  // populate the type cache, without applying a different branch's constraints.
7395
7463
  const finalConstraints = expandedArgTypes.length > 1
@@ -7518,10 +7586,13 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7518
7586
  name: arg.d.name,
7519
7587
  }));
7520
7588
  const sources = node.d.args.map((arg) => getTypeOfExpression(arg.d.valueExpr));
7521
- if (sources.some((s) => s.isIncomplete || s.typeErrors || (0, types_1.isAny)(s.type) || !(0, overloadResultSelector_1.isFixedOverloadArgumentShape)(s.type, budget))) {
7589
+ const receiver = node.d.leftExpr.nodeType === 35 /* ParseNodeType.MemberAccess */
7590
+ ? getTypeOfExpression(node.d.leftExpr.d.leftExpr)
7591
+ : undefined;
7592
+ if ([...sources, ...(receiver ? [receiver] : [])].some((s) => s.isIncomplete || s.typeErrors || (0, types_1.isAny)(s.type) || !(0, overloadResultSelector_1.isFixedOverloadArgumentShape)(s.type, budget))) {
7522
7593
  return decline('unsupported-argument-shape');
7523
7594
  }
7524
- if (!sources.some((s) => (0, overloadResultSelector_1.hasNestedOverloadAny)(s.type))) {
7595
+ if (![...sources, ...(receiver ? [receiver] : [])].some((s) => (0, overloadResultSelector_1.hasNestedOverloadAny)(s.type))) {
7525
7596
  return decline('no-invariant-any');
7526
7597
  }
7527
7598
  const returns = [];
@@ -7531,10 +7602,22 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7531
7602
  const declaration = overload.shared.declaration;
7532
7603
  const declaredReturnType = overload.shared.declaredReturnType;
7533
7604
  const returnType = types_1.FunctionType.getEffectiveReturnType(overload);
7605
+ const receiverParam = overload.priv.strippedFirstParamType;
7606
+ const supportedBinding = receiver
7607
+ ? declaration?.isMethod &&
7608
+ types_1.FunctionType.isInstanceMethod(overload) &&
7609
+ overload.priv.boundToType &&
7610
+ (0, types_1.isClassInstance)(overload.priv.boundToType) &&
7611
+ receiverParam &&
7612
+ (0, types_1.isClassInstance)(receiverParam) &&
7613
+ (0, types_1.isClassInstance)(receiver.type) &&
7614
+ types_1.ClassType.isSameGenericClass(receiver.type, receiverParam) &&
7615
+ overload.shared.methodClass &&
7616
+ types_1.ClassType.isSameGenericClass(receiver.type, types_1.ClassType.cloneAsInstance(overload.shared.methodClass)) &&
7617
+ (0, overloadResultSelector_1.isFixedOverloadArgumentShape)(receiverParam, budget)
7618
+ : !declaration?.isMethod && !overload.shared.methodClass && !overload.priv.boundToType;
7534
7619
  if (!declaration ||
7535
- declaration.isMethod ||
7536
- overload.shared.methodClass ||
7537
- overload.priv.boundToType ||
7620
+ !supportedBinding ||
7538
7621
  overload.shared.typeParams.length ||
7539
7622
  !declaredReturnType ||
7540
7623
  !returnType ||
@@ -7576,6 +7659,9 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7576
7659
  continue;
7577
7660
  }
7578
7661
  const proof = mapping.argParams.map((p, i) => (0, overloadResultSelector_1.getFixedOverloadCoverage)(sources[i].type, p.paramType, budget));
7662
+ if (receiver && receiverParam) {
7663
+ proof.unshift((0, overloadResultSelector_1.getFixedOverloadCoverage)(receiver.type, receiverParam, budget));
7664
+ }
7579
7665
  const covered = proof.includes('unsupported')
7580
7666
  ? 'unsupported'
7581
7667
  : proof.includes('not-covered')
@@ -7600,11 +7686,12 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7600
7686
  : decline('equivalent-or-single-return');
7601
7687
  });
7602
7688
  }
7603
- function validateOverloadedArgTypes(errorNode, argList, typeResult, constraints, skipUnknownArgCheck, inferenceContext) {
7689
+ function validateOverloadedArgTypes(errorNode, argList, typeResult, constraints, skipUnknownArgCheck, inferenceContext, candidateOverloads) {
7604
7690
  const filteredMatchResults = [];
7605
7691
  let contextFreeArgTypes;
7606
7692
  let isTypeIncomplete = !!typeResult.isIncomplete;
7607
7693
  const type = typeResult.type;
7694
+ const overloads = candidateOverloads ?? types_1.OverloadedType.getOverloads(type);
7608
7695
  const speculativeNode = getSpeculativeNodeForCall(errorNode);
7609
7696
  // Start by evaluating the types of the arguments without any expected
7610
7697
  // type. Also, filter the list of overloads based on the number of
@@ -7613,7 +7700,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7613
7700
  // cache or record any diagnostics at this stage.
7614
7701
  useSpeculativeMode(speculativeNode, () => {
7615
7702
  let overloadIndex = 0;
7616
- types_1.OverloadedType.getOverloads(type).forEach((overload) => {
7703
+ overloads.forEach((overload) => {
7617
7704
  // Consider only the functions that have the @overload decorator,
7618
7705
  // not the final function that omits the overload. This is the
7619
7706
  // intended behavior according to PEP 484.
@@ -7630,7 +7717,6 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7630
7717
  // Skip the error message if we're in speculative mode because it's very
7631
7718
  // expensive, and we're going to suppress the diagnostic anyway.
7632
7719
  if (!canSkipDiagnosticForNode(errorNode)) {
7633
- const overloads = types_1.OverloadedType.getOverloads(type);
7634
7720
  const functionName = overloads.length > 0 && overloads[0].shared.name
7635
7721
  ? overloads[0].shared.name
7636
7722
  : '<anonymous function>';
@@ -7685,7 +7771,8 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7685
7771
  }
7686
7772
  let expandedArgTypes = [argList.map((arg) => undefined)];
7687
7773
  while (true) {
7688
- const callResult = validateOverloadsWithExpandedTypes(errorNode, expandedArgTypes, filteredMatchResults, constraints, skipUnknownArgCheck, inferenceContext);
7774
+ const callResult = validateOverloadsWithExpandedTypes(errorNode, expandedArgTypes, filteredMatchResults, constraints, skipUnknownArgCheck, inferenceContext,
7775
+ /* skipFinalValidation */ candidateOverloads !== undefined);
7689
7776
  if (callResult.isTypeIncomplete) {
7690
7777
  isTypeIncomplete = true;
7691
7778
  }
@@ -7820,24 +7907,51 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
7820
7907
  }), exprNode);
7821
7908
  return { returnType: types_1.UnknownType.create(), argumentErrors: true, overloadsUsedForCall };
7822
7909
  }
7823
- let returnType = mapSubtypesExpandTypeVars(callTypeResult.type, { sortSubtypes: true }, (expandedSubtype, unexpandedSubtype, isLastIteration) => {
7824
- return useSpeculativeMode(isLastIteration ? undefined : getSpeculativeNodeForCall(errorNode), () => {
7825
- const callResult = validateCallArgsForSubtype(errorNode, argList, expandedSubtype, unexpandedSubtype, !!callTypeResult.isIncomplete, constraints, skipUnknownArgCheck, inferenceContext, recursionCount);
7826
- if (callResult.argumentErrors) {
7827
- argumentErrors = true;
7828
- }
7829
- if (callResult.isTypeIncomplete) {
7830
- isTypeIncomplete = true;
7831
- }
7832
- if (callResult.overloadsUsedForCall) {
7833
- (0, collectionUtils_1.appendArray)(overloadsUsedForCall, callResult.overloadsUsedForCall);
7910
+ const concreteCallType = makeTopLevelTypeVarsConcrete(callTypeResult.type);
7911
+ const lambdaNodes = (0, types_1.isUnion)(concreteCallType)
7912
+ ? argList
7913
+ .map((arg) => arg.valueExpression)
7914
+ .filter((node) => node?.nodeType === 33 /* ParseNodeType.Lambda */)
7915
+ : undefined;
7916
+ const lambdaTypeCache = lambdaNodes?.length
7917
+ ? { lambdaNodes, entries: new Map(), branchIndex: 0 }
7918
+ : undefined;
7919
+ const previousCache = contextualLambdaTypeCache;
7920
+ let returnType;
7921
+ try {
7922
+ if (lambdaTypeCache) {
7923
+ contextualLambdaTypeCache = lambdaTypeCache;
7924
+ }
7925
+ returnType = mapSubtypesExpandTypeVars(callTypeResult.type, { sortSubtypes: true }, (expandedSubtype, unexpandedSubtype, isLastIteration) => {
7926
+ if (lambdaTypeCache) {
7927
+ lambdaTypeCache.branchIndex++;
7834
7928
  }
7835
- specializedInitSelfType = callResult.specializedInitSelfType;
7836
- return callResult.returnType;
7837
- }, {
7838
- allowDiagnostics: true,
7929
+ return useSpeculativeMode(isLastIteration ? undefined : getSpeculativeNodeForCall(errorNode), () => {
7930
+ const callResult = validateCallArgsForSubtype(errorNode, argList, expandedSubtype, unexpandedSubtype, !!callTypeResult.isIncomplete, constraints, skipUnknownArgCheck, inferenceContext, recursionCount);
7931
+ if (callResult.argumentErrors) {
7932
+ argumentErrors = true;
7933
+ }
7934
+ if (callResult.isTypeIncomplete) {
7935
+ isTypeIncomplete = true;
7936
+ }
7937
+ if (callResult.overloadsUsedForCall) {
7938
+ (0, collectionUtils_1.appendArray)(overloadsUsedForCall, callResult.overloadsUsedForCall);
7939
+ }
7940
+ specializedInitSelfType = callResult.specializedInitSelfType;
7941
+ return callResult.returnType;
7942
+ }, {
7943
+ allowDiagnostics: true,
7944
+ });
7839
7945
  });
7840
- });
7946
+ }
7947
+ finally {
7948
+ contextualLambdaTypeCache = previousCache;
7949
+ }
7950
+ // Keep branch-specific checking and return inference separate from the
7951
+ // combined contextual types retained for subsequent queries.
7952
+ if (!isTypeIncomplete && lambdaTypeCache && lambdaTypeCache.branchIndex > 1) {
7953
+ (0, cancellationUtils_1.invalidateTypeCacheIfCanceled)(() => combineContextualLambdaTypes(lambdaTypeCache));
7954
+ }
7841
7955
  // If we ended up with a "Never" type because all code paths returned
7842
7956
  // undefined due to argument errors, transform the result into an Unknown
7843
7957
  // to avoid subsequent false positives.
@@ -8037,6 +8151,110 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
8037
8151
  }
8038
8152
  return { symbol, symbolName, classType, hasImplementation };
8039
8153
  }
8154
+ // The synthesized "get" and "pop" methods for a TypedDict include a
8155
+ // catch-all overload that accepts any str key. When the key argument is a
8156
+ // union of str literals, that catch-all overload matches before union
8157
+ // expansion is attempted, which produces an overly-wide return type. This
8158
+ // function evaluates the call separately for each literal key subtype
8159
+ // (speculatively) and, if every subtype is accepted, returns the union of
8160
+ // the resulting return types.
8161
+ function refineTypedDictMethodCallForUnionKey(errorNode, argList, overloadedType, isCallTypeIncomplete, constraints, inferenceContext) {
8162
+ const overloads = types_1.OverloadedType.getOverloads(overloadedType);
8163
+ const overload = overloads[0];
8164
+ if (!overload || !types_1.FunctionType.isSynthesizedMethod(overload)) {
8165
+ return undefined;
8166
+ }
8167
+ const methodName = overload.shared.name;
8168
+ if (methodName !== 'get' && methodName !== 'pop') {
8169
+ return undefined;
8170
+ }
8171
+ const isBound = (0, types_1.isMethodType)(overload);
8172
+ const receiverType = isBound
8173
+ ? overload.priv.strippedFirstParamType
8174
+ : overload.shared.parameters.length > 0
8175
+ ? types_1.FunctionType.getParamType(overload, 0)
8176
+ : undefined;
8177
+ if (!receiverType || !(0, types_1.isClassInstance)(receiverType) || !types_1.ClassType.isTypedDictClass(receiverType)) {
8178
+ return undefined;
8179
+ }
8180
+ // Unbound generic methods have not specialized their field types from the
8181
+ // receiver. Keep the normal result rather than refining it to Unknown.
8182
+ if (!isBound &&
8183
+ ((0, typeUtils_1.requiresSpecialization)(receiverType) || (0, typeUtils_1.containsAnyOrUnknown)(receiverType, /* recurse */ true))) {
8184
+ return undefined;
8185
+ }
8186
+ // Handle only simple positional calls: (key) or (key, default).
8187
+ const keyIndex = isBound ? 0 : 1;
8188
+ if (argList.length <= keyIndex || argList.length > keyIndex + 2) {
8189
+ return undefined;
8190
+ }
8191
+ if (!argList.every((arg) => !arg.name && arg.argCategory === 0 /* ArgCategory.Simple */)) {
8192
+ return undefined;
8193
+ }
8194
+ const keyArg = argList[keyIndex];
8195
+ const keyTypeResult = keyArg.typeResult ?? (keyArg.valueExpression ? getTypeOfExpression(keyArg.valueExpression) : undefined);
8196
+ if (!keyTypeResult || !(0, types_1.isUnion)(keyTypeResult.type)) {
8197
+ return undefined;
8198
+ }
8199
+ // Every subtype must be a str literal; otherwise keep the normal result.
8200
+ const keySubtypes = [];
8201
+ let allStrLiterals = true;
8202
+ (0, typeUtils_1.doForEachSubtype)(keyTypeResult.type, (subtype) => {
8203
+ if ((0, types_1.isClassInstance)(subtype) &&
8204
+ types_1.ClassType.isBuiltIn(subtype, 'str') &&
8205
+ typeof subtype.priv.literalValue === 'string') {
8206
+ keySubtypes.push(subtype);
8207
+ }
8208
+ else {
8209
+ allStrLiterals = false;
8210
+ }
8211
+ });
8212
+ if (!allStrLiterals || keySubtypes.length < 2 || keySubtypes.length > maxSingleOverloadArgTypeExpansionCount) {
8213
+ return undefined;
8214
+ }
8215
+ let isTypeIncomplete = !!keyTypeResult.isIncomplete;
8216
+ const returnTypes = [];
8217
+ const overloadsUsedForCall = new Set();
8218
+ const succeeded = useSpeculativeMode(getSpeculativeNodeForCall(errorNode), () => {
8219
+ for (const keySubtype of keySubtypes) {
8220
+ // Avoid revalidating unrelated keys and their default parameters.
8221
+ const candidates = overloads.filter((candidate) => {
8222
+ const paramType = types_1.FunctionType.getParamType(candidate, keyIndex);
8223
+ return ((0, types_1.isClassInstance)(paramType) &&
8224
+ types_1.ClassType.isBuiltIn(paramType, 'str') &&
8225
+ (paramType.priv.literalValue === undefined ||
8226
+ paramType.priv.literalValue === keySubtype.priv.literalValue));
8227
+ });
8228
+ if (candidates.length === 0) {
8229
+ return false;
8230
+ }
8231
+ const subtypeArgList = [...argList];
8232
+ subtypeArgList[keyIndex] = {
8233
+ argCategory: 0 /* ArgCategory.Simple */,
8234
+ typeResult: { type: keySubtype, isIncomplete: keyTypeResult.isIncomplete },
8235
+ };
8236
+ const subtypeResult = validateOverloadedArgTypes(errorNode, subtypeArgList, { type: overloadedType, isIncomplete: isCallTypeIncomplete }, constraints?.clone(),
8237
+ /* skipUnknownArgCheck */ true, inferenceContext, candidates);
8238
+ if (subtypeResult.isTypeIncomplete) {
8239
+ isTypeIncomplete = true;
8240
+ }
8241
+ if (subtypeResult.argumentErrors || !subtypeResult.returnType) {
8242
+ return false;
8243
+ }
8244
+ returnTypes.push(subtypeResult.returnType);
8245
+ subtypeResult.overloadsUsedForCall?.forEach((matched) => overloadsUsedForCall.add(matched));
8246
+ }
8247
+ return true;
8248
+ });
8249
+ if (!succeeded) {
8250
+ return undefined;
8251
+ }
8252
+ return {
8253
+ returnType: (0, types_1.combineTypes)(returnTypes),
8254
+ isTypeIncomplete,
8255
+ overloadsUsedForCall: [...overloadsUsedForCall],
8256
+ };
8257
+ }
8040
8258
  function validateCallForOverloaded(errorNode, argList, expandedCallType, isCallTypeIncomplete, constraints, skipUnknownArgCheck, inferenceContext) {
8041
8259
  const overloads = types_1.OverloadedType.getOverloads(expandedCallType);
8042
8260
  // Handle the 'cast' call as a special case.
@@ -8049,11 +8267,19 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
8049
8267
  let returnType = callResult.returnType ?? types_1.UnknownType.create();
8050
8268
  let isTypeIncomplete = !!callResult.isTypeIncomplete;
8051
8269
  let argumentErrors = !!callResult.argumentErrors;
8270
+ let overloadsUsedForCall = callResult.overloadsUsedForCall;
8052
8271
  if (!argumentErrors) {
8272
+ const refinedResult = refineTypedDictMethodCallForUnionKey(errorNode, argList, expandedCallType, isCallTypeIncomplete, constraints, inferenceContext);
8273
+ if (refinedResult?.isTypeIncomplete) {
8274
+ isTypeIncomplete = true;
8275
+ }
8276
+ if (refinedResult) {
8277
+ overloadsUsedForCall = refinedResult.overloadsUsedForCall;
8278
+ }
8053
8279
  // Call the function transform logic to handle special-cased functions.
8054
8280
  const transformed = (0, functionTransform_1.applyFunctionTransform)(evaluatorInterface, errorNode, argList, expandedCallType, {
8055
8281
  argumentErrors: !!callResult.argumentErrors,
8056
- returnType: callResult.returnType ?? types_1.UnknownType.create(isTypeIncomplete),
8282
+ returnType: refinedResult?.returnType ?? callResult.returnType ?? types_1.UnknownType.create(isTypeIncomplete),
8057
8283
  isTypeIncomplete,
8058
8284
  });
8059
8285
  returnType = transformed.returnType;
@@ -8068,7 +8294,7 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
8068
8294
  returnType,
8069
8295
  isTypeIncomplete,
8070
8296
  argumentErrors,
8071
- overloadsUsedForCall: callResult.overloadsUsedForCall,
8297
+ overloadsUsedForCall,
8072
8298
  specializedInitSelfType: callResult.specializedInitSelfType,
8073
8299
  };
8074
8300
  }
@@ -11496,6 +11722,9 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
11496
11722
  }
11497
11723
  }
11498
11724
  }
11725
+ if (expectedType && !forceSpeculative && !isIncomplete) {
11726
+ captureContextualLambdaTypes(node);
11727
+ }
11499
11728
  }, {
11500
11729
  dependentType: inferenceContext?.expectedType,
11501
11730
  allowDiagnostics: !forceSpeculative && !canSkipDiagnosticForNode(node) && !inferenceContext?.isTypeIncomplete,
@@ -11506,7 +11735,11 @@ function createTypeEvaluator(importLookup, evaluatorOptions, wrapWithLogger) {
11506
11735
  if (expectedType && !assignType(expectedType, functionType)) {
11507
11736
  typeErrors = true;
11508
11737
  }
11509
- return { type: functionType, isIncomplete, typeErrors };
11738
+ const typeResult = { type: functionType, isIncomplete, typeErrors };
11739
+ if (expectedType && !forceSpeculative && !isIncomplete) {
11740
+ captureContextualLambdaTypes(node, typeResult);
11741
+ }
11742
+ return typeResult;
11510
11743
  });
11511
11744
  }
11512
11745
  function getTypeOfComprehension(node, flags, inferenceContext) {