@zzzen/pyright-internal 1.2.0-dev.20260222 → 1.2.0-dev.20260422

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 (219) hide show
  1. package/dist/analyzer/backgroundAnalysisProgram.d.ts +1 -1
  2. package/dist/analyzer/backgroundAnalysisProgram.js +9 -6
  3. package/dist/analyzer/backgroundAnalysisProgram.js.map +1 -1
  4. package/dist/analyzer/binder.d.ts +10 -1
  5. package/dist/analyzer/binder.js +258 -41
  6. package/dist/analyzer/binder.js.map +1 -1
  7. package/dist/analyzer/cellChainIndex.d.ts +34 -0
  8. package/dist/analyzer/cellChainIndex.js +126 -0
  9. package/dist/analyzer/cellChainIndex.js.map +1 -0
  10. package/dist/analyzer/checker.js +0 -1
  11. package/dist/analyzer/checker.js.map +1 -1
  12. package/dist/analyzer/codeFlowEngine.js +16 -1
  13. package/dist/analyzer/codeFlowEngine.js.map +1 -1
  14. package/dist/analyzer/constructors.js +9 -2
  15. package/dist/analyzer/constructors.js.map +1 -1
  16. package/dist/analyzer/importResolver.d.ts +3 -21
  17. package/dist/analyzer/importResolver.js +42 -316
  18. package/dist/analyzer/importResolver.js.map +1 -1
  19. package/dist/analyzer/importResolverFileSystem.d.ts +3 -0
  20. package/dist/analyzer/importResolverFileSystem.js +160 -0
  21. package/dist/analyzer/importResolverFileSystem.js.map +1 -0
  22. package/dist/analyzer/importResolverTypes.d.ts +24 -0
  23. package/dist/analyzer/importResolverTypes.js +8 -0
  24. package/dist/analyzer/importResolverTypes.js.map +1 -0
  25. package/dist/analyzer/importStatementUtils.js +9 -0
  26. package/dist/analyzer/importStatementUtils.js.map +1 -1
  27. package/dist/analyzer/parseTreeUtils.d.ts +1 -0
  28. package/dist/analyzer/parseTreeUtils.js +24 -7
  29. package/dist/analyzer/parseTreeUtils.js.map +1 -1
  30. package/dist/analyzer/patternMatching.js +14 -2
  31. package/dist/analyzer/patternMatching.js.map +1 -1
  32. package/dist/analyzer/program.d.ts +5 -3
  33. package/dist/analyzer/program.js +40 -51
  34. package/dist/analyzer/program.js.map +1 -1
  35. package/dist/analyzer/pythonPathUtils.d.ts +1 -1
  36. package/dist/analyzer/pythonPathUtils.js +3 -1
  37. package/dist/analyzer/pythonPathUtils.js.map +1 -1
  38. package/dist/analyzer/scope.d.ts +10 -1
  39. package/dist/analyzer/scope.js +14 -1
  40. package/dist/analyzer/scope.js.map +1 -1
  41. package/dist/analyzer/service.d.ts +11 -6
  42. package/dist/analyzer/service.js +82 -83
  43. package/dist/analyzer/service.js.map +1 -1
  44. package/dist/analyzer/sourceEnumerator.d.ts +3 -0
  45. package/dist/analyzer/sourceEnumerator.js +27 -1
  46. package/dist/analyzer/sourceEnumerator.js.map +1 -1
  47. package/dist/analyzer/sourceFile.d.ts +2 -1
  48. package/dist/analyzer/sourceFile.js +2 -2
  49. package/dist/analyzer/sourceFile.js.map +1 -1
  50. package/dist/analyzer/sourceFileInfo.d.ts +4 -0
  51. package/dist/analyzer/sourceFileInfo.js +9 -0
  52. package/dist/analyzer/sourceFileInfo.js.map +1 -1
  53. package/dist/analyzer/sourceMapper.d.ts +1 -0
  54. package/dist/analyzer/sourceMapper.js +44 -0
  55. package/dist/analyzer/sourceMapper.js.map +1 -1
  56. package/dist/analyzer/tuples.js +3 -1
  57. package/dist/analyzer/tuples.js.map +1 -1
  58. package/dist/analyzer/typeEvaluator.js +102 -51
  59. package/dist/analyzer/typeEvaluator.js.map +1 -1
  60. package/dist/analyzer/typeEvaluatorTypes.d.ts +2 -0
  61. package/dist/analyzer/typeEvaluatorTypes.js +4 -0
  62. package/dist/analyzer/typeEvaluatorTypes.js.map +1 -1
  63. package/dist/analyzer/typeGuards.js +28 -6
  64. package/dist/analyzer/typeGuards.js.map +1 -1
  65. package/dist/analyzer/typeStubWriter.d.ts +15 -50
  66. package/dist/analyzer/typeStubWriter.js +91 -9
  67. package/dist/analyzer/typeStubWriter.js.map +1 -1
  68. package/dist/analyzer/typeUtils.d.ts +1 -0
  69. package/dist/analyzer/typeUtils.js +27 -3
  70. package/dist/analyzer/typeUtils.js.map +1 -1
  71. package/dist/analyzer/typeshedInfoProvider.d.ts +2 -0
  72. package/dist/analyzer/typeshedInfoProvider.js +232 -0
  73. package/dist/analyzer/typeshedInfoProvider.js.map +1 -0
  74. package/dist/backgroundAnalysisBase.d.ts +3 -3
  75. package/dist/backgroundAnalysisBase.js +12 -9
  76. package/dist/backgroundAnalysisBase.js.map +1 -1
  77. package/dist/commands/createTypeStub.d.ts +16 -8
  78. package/dist/commands/createTypeStub.js +58 -36
  79. package/dist/commands/createTypeStub.js.map +1 -1
  80. package/dist/common/cancellationUtils.d.ts +7 -0
  81. package/dist/common/cancellationUtils.js +34 -0
  82. package/dist/common/cancellationUtils.js.map +1 -1
  83. package/dist/common/collectionUtils.d.ts +3 -3
  84. package/dist/common/collectionUtils.js.map +1 -1
  85. package/dist/common/core.d.ts +1 -1
  86. package/dist/common/core.js.map +1 -1
  87. package/dist/common/crypto.js +11 -0
  88. package/dist/common/crypto.js.map +1 -1
  89. package/dist/common/extensibility.d.ts +7 -0
  90. package/dist/common/extensibility.js.map +1 -1
  91. package/dist/common/fullAccessHost.js +4 -2
  92. package/dist/common/fullAccessHost.js.map +1 -1
  93. package/dist/common/pathUtils.d.ts +4 -1
  94. package/dist/common/pathUtils.js.map +1 -1
  95. package/dist/common/realFileSystem.js +42 -3
  96. package/dist/common/realFileSystem.js.map +1 -1
  97. package/dist/common/serviceKeys.d.ts +3 -0
  98. package/dist/common/serviceKeys.js +2 -0
  99. package/dist/common/serviceKeys.js.map +1 -1
  100. package/dist/common/serviceProviderExtensions.js.map +1 -1
  101. package/dist/common/uri/uriUtils.d.ts +4 -0
  102. package/dist/common/uri/uriUtils.js +19 -3
  103. package/dist/common/uri/uriUtils.js.map +1 -1
  104. package/dist/common/workspaceEditUtils.js +0 -2
  105. package/dist/common/workspaceEditUtils.js.map +1 -1
  106. package/dist/languageServerBase.d.ts +1 -0
  107. package/dist/languageServerBase.js +6 -0
  108. package/dist/languageServerBase.js.map +1 -1
  109. package/dist/languageService/completionProvider.d.ts +6 -0
  110. package/dist/languageService/completionProvider.js +252 -75
  111. package/dist/languageService/completionProvider.js.map +1 -1
  112. package/dist/languageService/definitionProvider.js +1 -1
  113. package/dist/languageService/definitionProvider.js.map +1 -1
  114. package/dist/languageService/documentSymbolCollector.js +34 -4
  115. package/dist/languageService/documentSymbolCollector.js.map +1 -1
  116. package/dist/languageService/dynamicFeature.d.ts +3 -0
  117. package/dist/languageService/dynamicFeature.js +5 -0
  118. package/dist/languageService/dynamicFeature.js.map +1 -1
  119. package/dist/languageService/hoverProvider.d.ts +2 -1
  120. package/dist/languageService/hoverProvider.js +13 -5
  121. package/dist/languageService/hoverProvider.js.map +1 -1
  122. package/dist/languageService/pullDiagnosticsDynamicFeature.d.ts +1 -0
  123. package/dist/languageService/pullDiagnosticsDynamicFeature.js +4 -0
  124. package/dist/languageService/pullDiagnosticsDynamicFeature.js.map +1 -1
  125. package/dist/languageService/referencesProvider.js +5 -4
  126. package/dist/languageService/referencesProvider.js.map +1 -1
  127. package/dist/languageService/signatureHelpProvider.d.ts +1 -0
  128. package/dist/languageService/signatureHelpProvider.js +76 -2
  129. package/dist/languageService/signatureHelpProvider.js.map +1 -1
  130. package/dist/languageService/symbolIndexer.d.ts +1 -0
  131. package/dist/languageService/symbolIndexer.js.map +1 -1
  132. package/dist/languageService/tooltipUtils.d.ts +11 -4
  133. package/dist/languageService/tooltipUtils.js +195 -7
  134. package/dist/languageService/tooltipUtils.js.map +1 -1
  135. package/dist/parser/tokenizer.js +6 -2
  136. package/dist/parser/tokenizer.js.map +1 -1
  137. package/dist/partialStubService.d.ts +11 -0
  138. package/dist/partialStubService.js +23 -1
  139. package/dist/partialStubService.js.map +1 -1
  140. package/dist/pyright.js +13 -2
  141. package/dist/pyright.js.map +1 -1
  142. package/dist/tests/chainedSourceFiles.test.js +138 -0
  143. package/dist/tests/chainedSourceFiles.test.js.map +1 -1
  144. package/dist/tests/checker.test.js +12 -0
  145. package/dist/tests/checker.test.js.map +1 -1
  146. package/dist/tests/completions.test.js +328 -0
  147. package/dist/tests/completions.test.js.map +1 -1
  148. package/dist/tests/config.test.js +54 -0
  149. package/dist/tests/config.test.js.map +1 -1
  150. package/dist/tests/filesystem.test.js +44 -0
  151. package/dist/tests/filesystem.test.js.map +1 -1
  152. package/dist/tests/fourSlashRunner.test.js +1 -1
  153. package/dist/tests/fourSlashRunner.test.js.map +1 -1
  154. package/dist/tests/fourslash/findDefinitions.definitionFilter.preferSource.fourslash.js +25 -1
  155. package/dist/tests/fourslash/findDefinitions.definitionFilter.preferSource.fourslash.js.map +1 -1
  156. package/dist/tests/fourslash/import.multipart3.fourslash.d.ts +1 -0
  157. package/dist/tests/fourslash/import.multipart3.fourslash.js +46 -0
  158. package/dist/tests/fourslash/import.multipart3.fourslash.js.map +1 -0
  159. package/dist/tests/fourslash/import.pytyped.unsupportedDunderAll.fourslash.d.ts +1 -0
  160. package/dist/tests/fourslash/import.pytyped.unsupportedDunderAll.fourslash.js +33 -0
  161. package/dist/tests/fourslash/import.pytyped.unsupportedDunderAll.fourslash.js.map +1 -0
  162. package/dist/tests/harness/fourslash/runner.d.ts +4 -4
  163. package/dist/tests/harness/fourslash/runner.js +5 -5
  164. package/dist/tests/harness/fourslash/runner.js.map +1 -1
  165. package/dist/tests/harness/fourslash/testState.d.ts +20 -5
  166. package/dist/tests/harness/fourslash/testState.js +11 -26
  167. package/dist/tests/harness/fourslash/testState.js.map +1 -1
  168. package/dist/tests/harness/fourslash/testStateUtils.js +2 -0
  169. package/dist/tests/harness/fourslash/testStateUtils.js.map +1 -1
  170. package/dist/tests/harness/testAccessHost.d.ts +3 -1
  171. package/dist/tests/harness/testAccessHost.js +6 -2
  172. package/dist/tests/harness/testAccessHost.js.map +1 -1
  173. package/dist/tests/harness/testHost.js +20 -18
  174. package/dist/tests/harness/testHost.js.map +1 -1
  175. package/dist/tests/harness/vfs/factory.js +4 -1
  176. package/dist/tests/harness/vfs/factory.js.map +1 -1
  177. package/dist/tests/harness/vfs/filesystem.d.ts +8 -1
  178. package/dist/tests/harness/vfs/filesystem.js +84 -30
  179. package/dist/tests/harness/vfs/filesystem.js.map +1 -1
  180. package/dist/tests/hoverProvider.test.js +290 -0
  181. package/dist/tests/hoverProvider.test.js.map +1 -1
  182. package/dist/tests/importResolverSupport.test.d.ts +1 -0
  183. package/dist/tests/importResolverSupport.test.js +319 -0
  184. package/dist/tests/importResolverSupport.test.js.map +1 -0
  185. package/dist/tests/importStatementUtils.test.js +66 -0
  186. package/dist/tests/importStatementUtils.test.js.map +1 -1
  187. package/dist/tests/lsp/{webpack.testserver.config.d.ts → rspack.testserver.config.d.ts} +1 -1
  188. package/dist/tests/lsp/{webpack.testserver.config.js → rspack.testserver.config.js} +4 -11
  189. package/dist/tests/lsp/rspack.testserver.config.js.map +1 -0
  190. package/dist/tests/realTempFile.test.d.ts +1 -0
  191. package/dist/tests/realTempFile.test.js +144 -0
  192. package/dist/tests/realTempFile.test.js.map +1 -0
  193. package/dist/tests/service.test.js +182 -3
  194. package/dist/tests/service.test.js.map +1 -1
  195. package/dist/tests/signatureHelp.test.js +391 -6
  196. package/dist/tests/signatureHelp.test.js.map +1 -1
  197. package/dist/tests/testState.test.js +19 -0
  198. package/dist/tests/testState.test.js.map +1 -1
  199. package/dist/tests/tokenizer.test.js +42 -0
  200. package/dist/tests/tokenizer.test.js.map +1 -1
  201. package/dist/tests/typeEvaluator1.test.js +4 -0
  202. package/dist/tests/typeEvaluator1.test.js.map +1 -1
  203. package/dist/tests/typeEvaluator2.test.js +12 -0
  204. package/dist/tests/typeEvaluator2.test.js.map +1 -1
  205. package/dist/tests/typeEvaluator3.test.js +8 -1
  206. package/dist/tests/typeEvaluator3.test.js.map +1 -1
  207. package/dist/tests/typeEvaluator6.test.js +7 -0
  208. package/dist/tests/typeEvaluator6.test.js.map +1 -1
  209. package/dist/tests/typeEvaluator8.test.js +13 -1
  210. package/dist/tests/typeEvaluator8.test.js.map +1 -1
  211. package/dist/tests/uri.test.js +29 -0
  212. package/dist/tests/uri.test.js.map +1 -1
  213. package/dist/tests/wildcardImportPackageMerge.test.d.ts +1 -0
  214. package/dist/tests/wildcardImportPackageMerge.test.js +97 -0
  215. package/dist/tests/wildcardImportPackageMerge.test.js.map +1 -0
  216. package/dist/tests/workspaceEditUtils.test.js +0 -1
  217. package/dist/tests/workspaceEditUtils.test.js.map +1 -1
  218. package/package.json +12 -11
  219. package/dist/tests/lsp/webpack.testserver.config.js.map +0 -1
@@ -264,6 +264,11 @@ class CompletionProvider {
264
264
  getCompletionItemData(item) {
265
265
  return (0, lspUtils_1.fromLSPAny)(item.data);
266
266
  }
267
+ addAdditionalExpressionCompletions(parseNode, priorWord, completionMap) {
268
+ // Default implementation is a no-op.
269
+ // Subclasses can override to inject additional completion items that are not produced by the
270
+ // core completion algorithm (e.g. product-specific synthesized completions).
271
+ }
267
272
  getMethodOverrideCompletions(priorWord, partialName, decorators) {
268
273
  const enclosingClass = ParseTreeUtils.getEnclosingClass(partialName, /* stopAtFunction */ true);
269
274
  if (!enclosingClass) {
@@ -441,7 +446,7 @@ class CompletionProvider {
441
446
  }
442
447
  // This call can be expensive to perform on every completion item
443
448
  // that we return, so we do it lazily in the "resolve" callback.
444
- const type = this.evaluator.getEffectiveTypeOfSymbol(symbol);
449
+ const type = this._getTypeOfSymbol(symbol, detail, name);
445
450
  if (!type) {
446
451
  // Can't resolve. so bail out.
447
452
  return;
@@ -737,6 +742,39 @@ class CompletionProvider {
737
742
  get _fileContents() {
738
743
  return this.parseResults?.text ?? '';
739
744
  }
745
+ _getTypeOfSymbol(symbol, detail, memberName) {
746
+ const originalType = this.evaluator.getEffectiveTypeOfSymbol(symbol);
747
+ if (!originalType) {
748
+ return undefined;
749
+ }
750
+ // If this completion item came from a member access on an object
751
+ // (as opposed to a name completion), compute the accessed type
752
+ // so descriptors report the correct type via __get__.
753
+ //
754
+ // Note that we intentionally exclude `property` here. `getTypeDetail` already
755
+ // understands `property` and includes the `(property)` suffix in hover/docs.
756
+ if (!detail.boundObjectOrClass || !types_1.TypeBase.isInstance(detail.boundObjectOrClass)) {
757
+ return originalType;
758
+ }
759
+ if ((0, typeUtils_1.isProperty)(originalType) || !(0, typeUtils_1.isMaybeDescriptorInstance)(originalType, /* requireSetter */ false)) {
760
+ return originalType;
761
+ }
762
+ const offset = (0, positionUtils_1.convertPositionToOffset)(this.position, this.parseResults.tokenizerOutput.lines);
763
+ if (offset === undefined) {
764
+ return originalType;
765
+ }
766
+ const node = ParseTreeUtils.findNodeByOffset(this.parseResults.parserOutput.parseTree, offset);
767
+ const memberAccessNode = node
768
+ ? ParseTreeUtils.getParentNodeOfType(node, 35 /* ParseNodeType.MemberAccess */)
769
+ : undefined;
770
+ if (!memberAccessNode || memberAccessNode.nodeType !== 35 /* ParseNodeType.MemberAccess */) {
771
+ return originalType;
772
+ }
773
+ const boundType = this.evaluator.getTypeOfBoundMember(memberAccessNode, detail.boundObjectOrClass, memberName,
774
+ /* usage */ undefined,
775
+ /* diag */ undefined, 0 /* MemberAccessFlags.Default */);
776
+ return boundType?.type ?? originalType;
777
+ }
740
778
  _getCompletions() {
741
779
  const offset = (0, positionUtils_1.convertPositionToOffset)(this.position, this.parseResults.tokenizerOutput.lines);
742
780
  if (offset === undefined) {
@@ -779,6 +817,18 @@ class CompletionProvider {
779
817
  }
780
818
  const curNode = ParseTreeUtils.findNodeByOffset(this.parseResults.parserOutput.parseTree, curOffset);
781
819
  if (curNode && curNode !== initialNode) {
820
+ if ((curNode.nodeType === 48 /* ParseNodeType.StringList */ ||
821
+ curNode.nodeType === 49 /* ParseNodeType.String */ ||
822
+ curNode.nodeType === 30 /* ParseNodeType.FormatString */) &&
823
+ !(textRange_1.TextRange.contains(curNode, offset) || textRange_1.TextRange.getEnd(curNode) === offset)) {
824
+ // When completing after something like a trailing comma, ParseTreeUtils may return the
825
+ // preceding string node even though the cursor is outside the string.
826
+ //
827
+ // In that case, intentionally stop scanning and keep the existing context node
828
+ // (typically a call). Continuing would only move further into the previous argument and
829
+ // could select an even more misleading context.
830
+ break;
831
+ }
782
832
  if (ParseTreeUtils.getNodeDepth(curNode) > initialDepth) {
783
833
  node = curNode;
784
834
  // If we're at the end of a list with a hanging comma, handle the
@@ -1396,6 +1446,7 @@ class CompletionProvider {
1396
1446
  /* atArgument */ false, completionMap);
1397
1447
  // Add symbols that are in scope.
1398
1448
  this._addSymbols(parseNode, priorWord, completionMap);
1449
+ this.addAdditionalExpressionCompletions(parseNode, priorWord, completionMap);
1399
1450
  // Add keywords.
1400
1451
  this._findMatchingKeywords(Keywords.forVersion(this.execEnv.pythonVersion), priorWord).map((keyword) => {
1401
1452
  if (completionMap.has(keyword)) {
@@ -1441,7 +1492,6 @@ class CompletionProvider {
1441
1492
  if (!atArgument) {
1442
1493
  this._addNamedParameters(signatureInfo, priorWord, completionMap);
1443
1494
  }
1444
- // Add literals that apply to this parameter.
1445
1495
  this._addLiteralValuesForArgument(signatureInfo, priorWord, priorText, postText, completionMap);
1446
1496
  }
1447
1497
  }
@@ -1640,48 +1690,9 @@ class CompletionProvider {
1640
1690
  if (!parentAndChild) {
1641
1691
  return false;
1642
1692
  }
1643
- // See if the type evaluator can determine the expected type for this node.
1644
- // ex) a: Literal["str"] = /* here */
1645
- const nodeForExpectedType = parentAndChild.parent.nodeType === 3 /* ParseNodeType.Assignment */
1646
- ? parentAndChild.parent.d.rightExpr === parentAndChild.child
1647
- ? parentAndChild.child
1648
- : undefined
1649
- : (0, parseNodes_1.isExpressionNode)(parentAndChild.child)
1650
- ? parentAndChild.child
1651
- : undefined;
1652
- const offset = (0, positionUtils_1.convertPositionToOffset)(this.position, this.parseResults.tokenizerOutput.lines);
1653
- const inCallArg = !!(0, parseTreeUtils_1.getCallNodeAndActiveParamIndex)(parseNode, offset, this.parseResults.tokenizerOutput.tokens);
1654
- if (nodeForExpectedType) {
1655
- const expectedTypeResult = this.evaluator.getExpectedType(nodeForExpectedType);
1656
- if (expectedTypeResult && (0, typeUtils_1.containsLiteralType)(expectedTypeResult.type)) {
1657
- this._addLiteralValuesForTargetType(expectedTypeResult.type, priorWord, priorText, postText, completionMap);
1658
- if (!inCallArg) {
1659
- return true;
1660
- }
1661
- }
1662
- }
1663
- // ex) a: TypedDictType = { "/* here */" } or a: TypedDictType = { A/* here */ }
1664
- const nodeForKey = parentAndChild.parent;
1665
- if (nodeForKey) {
1666
- // If the dictionary is not yet filled in, it will appear as though it's
1667
- // a set initially.
1668
- let dictOrSet;
1669
- if (nodeForKey.nodeType === 20 /* ParseNodeType.DictionaryKeyEntry */ &&
1670
- nodeForKey.d.keyExpr === parentAndChild.child &&
1671
- nodeForKey.parent?.nodeType === 18 /* ParseNodeType.Dictionary */) {
1672
- dictOrSet = nodeForKey.parent;
1673
- }
1674
- else if (nodeForKey?.nodeType === 45 /* ParseNodeType.Set */) {
1675
- dictOrSet = nodeForKey;
1676
- }
1677
- if (dictOrSet) {
1678
- if (this._tryAddTypedDictKeysFromDictionary(dictOrSet, parseNode.nodeType === 49 /* ParseNodeType.String */ ? parseNode : undefined, priorWord, priorText, postText, completionMap)) {
1679
- return true;
1680
- }
1681
- }
1682
- }
1683
1693
  // a: DictType = { .... }
1684
1694
  // a[/* here */] or a['/* here */'] or a[variable/*here*/]
1695
+ // Check subscript/index context BEFORE assignment context to prioritize TypedDict keys
1685
1696
  const argument = parentAndChild.parent;
1686
1697
  if (argument.nodeType === 1 /* ParseNodeType.Argument */ && argument.parent?.nodeType === 27 /* ParseNodeType.Index */) {
1687
1698
  const priorTextInString = parseNode.nodeType === 49 /* ParseNodeType.String */ ? priorText : '';
@@ -1719,15 +1730,62 @@ class CompletionProvider {
1719
1730
  return true;
1720
1731
  }
1721
1732
  }
1733
+ // See if the type evaluator can determine the expected type for this node.
1734
+ // ex) a: Literal["str"] = /* here */
1735
+ const nodeForExpectedType = parentAndChild.parent.nodeType === 3 /* ParseNodeType.Assignment */
1736
+ ? parentAndChild.parent.d.rightExpr === parentAndChild.child
1737
+ ? parentAndChild.child
1738
+ : undefined
1739
+ : (0, parseNodes_1.isExpressionNode)(parentAndChild.child)
1740
+ ? parentAndChild.child
1741
+ : undefined;
1742
+ const offset = (0, positionUtils_1.convertPositionToOffset)(this.position, this.parseResults.tokenizerOutput.lines);
1743
+ const inCallArg = !!(0, parseTreeUtils_1.getCallNodeAndActiveParamIndex)(parseNode, offset, this.parseResults.tokenizerOutput.tokens);
1744
+ if (nodeForExpectedType) {
1745
+ const expectedTypeResult = this.evaluator.getExpectedType(nodeForExpectedType);
1746
+ if (expectedTypeResult &&
1747
+ this._addLiteralValuesForExpectedTypes(nodeForExpectedType, expectedTypeResult, priorWord, priorText, postText, completionMap)) {
1748
+ if (!inCallArg) {
1749
+ return true;
1750
+ }
1751
+ }
1752
+ }
1753
+ // ex) a: TypedDictType = { "/* here */" } or a: TypedDictType = { A/* here */ }
1754
+ const nodeForKey = parentAndChild.parent;
1755
+ if (nodeForKey) {
1756
+ // If the dictionary is not yet filled in, it will appear as though it's
1757
+ // a set initially.
1758
+ let dictOrSet;
1759
+ if (nodeForKey.nodeType === 20 /* ParseNodeType.DictionaryKeyEntry */ &&
1760
+ nodeForKey.d.keyExpr === parentAndChild.child &&
1761
+ nodeForKey.parent?.nodeType === 18 /* ParseNodeType.Dictionary */) {
1762
+ dictOrSet = nodeForKey.parent;
1763
+ }
1764
+ else if (nodeForKey?.nodeType === 45 /* ParseNodeType.Set */) {
1765
+ dictOrSet = nodeForKey;
1766
+ }
1767
+ if (dictOrSet) {
1768
+ if (this._tryAddTypedDictKeysFromDictionary(dictOrSet, parseNode.nodeType === 49 /* ParseNodeType.String */ ? parseNode : undefined, priorWord, priorText, postText, completionMap)) {
1769
+ return true;
1770
+ }
1771
+ }
1772
+ }
1722
1773
  // if c == "/* here */"
1723
1774
  const comparison = parentAndChild.parent;
1724
1775
  const supportedOperators = [2 /* OperatorType.Assign */, 12 /* OperatorType.Equals */, 28 /* OperatorType.NotEquals */];
1725
1776
  if (comparison.nodeType === 7 /* ParseNodeType.BinaryOperation */ &&
1726
1777
  supportedOperators.includes(comparison.d.operator)) {
1727
1778
  const type = this.evaluator.getType(comparison.d.leftExpr);
1728
- if (type && (0, typeUtils_1.containsLiteralType)(type)) {
1729
- this._addLiteralValuesForTargetType(type, priorWord, priorText, postText, completionMap);
1730
- return true;
1779
+ if (type) {
1780
+ if ((0, typeUtils_1.containsLiteralType)(type)) {
1781
+ this._addLiteralValuesForTargetType(type, priorWord, priorText, postText, completionMap);
1782
+ return true;
1783
+ }
1784
+ const enumValueLiteralType = getStringLiteralValueTypeFromEnumType(this.evaluator, type);
1785
+ if (enumValueLiteralType) {
1786
+ this._addLiteralValuesForTargetType(enumValueLiteralType, priorWord, priorText, postText, completionMap);
1787
+ return true;
1788
+ }
1731
1789
  }
1732
1790
  }
1733
1791
  // if c := "/* here */"
@@ -1740,35 +1798,8 @@ class CompletionProvider {
1740
1798
  return true;
1741
1799
  }
1742
1800
  }
1743
- // For now, we only support simple cases. no complex pattern matching.
1744
- // match c:
1745
- // case /* here */
1746
- const caseNode = parentAndChild.parent;
1747
- if (caseNode.nodeType === 64 /* ParseNodeType.Case */ &&
1748
- caseNode.d.pattern.nodeType === 0 /* ParseNodeType.Error */ &&
1749
- caseNode.d.pattern.d.category === 11 /* ErrorExpressionCategory.MissingPattern */ &&
1750
- caseNode.d.suite === parentAndChild.child &&
1751
- caseNode.parent?.nodeType === 63 /* ParseNodeType.Match */) {
1752
- const type = this.evaluator.getType(caseNode.parent.d.expr);
1753
- if (type && (0, typeUtils_1.containsLiteralType)(type)) {
1754
- this._addLiteralValuesForTargetType(type, priorWord, priorText, postText, completionMap);
1755
- return true;
1756
- }
1757
- }
1758
- // match c:
1759
- // case "/* here */"
1760
- // case Sym/*here*/
1761
- const patternLiteral = parentAndChild.parent;
1762
- if ((patternLiteral.nodeType === 67 /* ParseNodeType.PatternLiteral */ ||
1763
- patternLiteral.nodeType === 69 /* ParseNodeType.PatternCapture */) &&
1764
- patternLiteral.parent?.nodeType === 66 /* ParseNodeType.PatternAs */ &&
1765
- patternLiteral.parent.parent?.nodeType === 64 /* ParseNodeType.Case */ &&
1766
- patternLiteral.parent.parent.parent?.nodeType === 63 /* ParseNodeType.Match */) {
1767
- const type = this.evaluator.getType(patternLiteral.parent.parent.parent.d.expr);
1768
- if (type && (0, typeUtils_1.containsLiteralType)(type)) {
1769
- this._addLiteralValuesForTargetType(type, priorWord, priorText, postText, completionMap);
1770
- return true;
1771
- }
1801
+ if (this._tryAddMatchCaseLiteralCompletions(parentAndChild, priorWord, priorText, postText, completionMap)) {
1802
+ return true;
1772
1803
  }
1773
1804
  if (parseNode.nodeType === 49 /* ParseNodeType.String */) {
1774
1805
  const offset = (0, positionUtils_1.convertPositionToOffset)(this.position, this.parseResults.tokenizerOutput.lines);
@@ -1777,6 +1808,33 @@ class CompletionProvider {
1777
1808
  return true;
1778
1809
  }
1779
1810
  return false;
1811
+ function getStringLiteralValueTypeFromEnumType(evaluator, type) {
1812
+ const enumValueTypes = [];
1813
+ (0, typeUtils_1.doForEachSubtype)(type, (subtype) => {
1814
+ if (!(0, types_1.isClassInstance)(subtype) || !types_1.ClassType.isEnumClass(subtype)) {
1815
+ return;
1816
+ }
1817
+ const enumClassType = types_1.ClassType.cloneAsInstantiable(subtype);
1818
+ const enumMemberSymbols = new Map();
1819
+ (0, typeUtils_1.getMembersForClass)(enumClassType, enumMemberSymbols, /* includeInstanceVars */ false);
1820
+ enumMemberSymbols.forEach((_, name) => {
1821
+ const enumMemberType = (0, enums_1.transformTypeForEnumMember)(evaluator, enumClassType, name);
1822
+ if (!enumMemberType || !(0, types_1.isClassInstance)(enumMemberType)) {
1823
+ return;
1824
+ }
1825
+ const literalValue = enumMemberType.priv.literalValue;
1826
+ if (!(literalValue instanceof types_1.EnumLiteral)) {
1827
+ return;
1828
+ }
1829
+ (0, typeUtils_1.doForEachSubtype)(literalValue.itemType, (valueSubtype) => {
1830
+ if ((0, types_1.isClassInstance)(valueSubtype) && typeof valueSubtype.priv.literalValue === 'string') {
1831
+ enumValueTypes.push(valueSubtype);
1832
+ }
1833
+ });
1834
+ });
1835
+ });
1836
+ return enumValueTypes.length > 0 ? (0, types_1.combineTypes)(enumValueTypes) : undefined;
1837
+ }
1780
1838
  function getParentSkippingStringList(node) {
1781
1839
  if (!node.parent) {
1782
1840
  return undefined;
@@ -1793,6 +1851,122 @@ class CompletionProvider {
1793
1851
  return { parent: node.parent.parent, child: node.parent };
1794
1852
  }
1795
1853
  }
1854
+ _tryAddMatchCaseLiteralCompletions(parentAndChild, priorWord, priorText, postText, completionMap) {
1855
+ // For now, we only support simple cases. no complex pattern matching.
1856
+ // match c:
1857
+ // case /* here */
1858
+ // and
1859
+ // match c:
1860
+ // case "/* here */"
1861
+ // case Sym/*here*/
1862
+ const parent = parentAndChild.parent;
1863
+ let matchNode;
1864
+ let caseNode;
1865
+ if (parent.nodeType === 64 /* ParseNodeType.Case */ &&
1866
+ parent.d.pattern.nodeType === 0 /* ParseNodeType.Error */ &&
1867
+ parent.d.pattern.d.category === 11 /* ErrorExpressionCategory.MissingPattern */ &&
1868
+ parent.d.suite === parentAndChild.child &&
1869
+ parent.parent?.nodeType === 63 /* ParseNodeType.Match */) {
1870
+ matchNode = parent.parent;
1871
+ caseNode = parent;
1872
+ }
1873
+ else if ((parent.nodeType === 67 /* ParseNodeType.PatternLiteral */ || parent.nodeType === 69 /* ParseNodeType.PatternCapture */) &&
1874
+ parent.parent?.nodeType === 66 /* ParseNodeType.PatternAs */ &&
1875
+ parent.parent.parent?.nodeType === 64 /* ParseNodeType.Case */ &&
1876
+ parent.parent.parent.parent?.nodeType === 63 /* ParseNodeType.Match */) {
1877
+ matchNode = parent.parent.parent.parent;
1878
+ caseNode = parent.parent.parent;
1879
+ }
1880
+ else {
1881
+ return false;
1882
+ }
1883
+ const type = this._getFilteredMatchSubjectTypeForCaseCompletions(matchNode, caseNode);
1884
+ if (type && (0, typeUtils_1.containsLiteralType)(type)) {
1885
+ this._addLiteralValuesForTargetType(type, priorWord, priorText, postText, completionMap);
1886
+ return true;
1887
+ }
1888
+ return false;
1889
+ }
1890
+ _addLiteralValuesForExpectedTypes(expressionNode, expectedTypeResult, priorWord, priorText, postText, completionMap) {
1891
+ if (!this._canUseExpectedTypeForLiteralCompletion(expressionNode, expectedTypeResult.node)) {
1892
+ return false;
1893
+ }
1894
+ let addedLiteralValues = false;
1895
+ for (const candidateType of expectedTypeResult.candidates) {
1896
+ if (!(0, typeUtils_1.containsLiteralType)(candidateType)) {
1897
+ continue;
1898
+ }
1899
+ this._addLiteralValuesForTargetType(candidateType, priorWord, priorText, postText, completionMap);
1900
+ addedLiteralValues = true;
1901
+ }
1902
+ return addedLiteralValues;
1903
+ }
1904
+ _canUseExpectedTypeForLiteralCompletion(expressionNode, expectedTypeNode) {
1905
+ return expressionNode === expectedTypeNode;
1906
+ }
1907
+ _getFilteredMatchSubjectTypeForCaseCompletions(matchNode, currentCaseNode) {
1908
+ const getPriorCaseStringLiteralValues = () => {
1909
+ const values = new Set();
1910
+ const currentIndex = matchNode.d.cases.findIndex((c) => c === currentCaseNode);
1911
+ if (currentIndex <= 0) {
1912
+ return values;
1913
+ }
1914
+ for (let i = 0; i < currentIndex; i++) {
1915
+ const caseNode = matchNode.d.cases[i];
1916
+ // Be conservative: a guard means the case may not actually match.
1917
+ if (caseNode.d.guardExpr) {
1918
+ continue;
1919
+ }
1920
+ addStringLiteralValuesFromPattern(caseNode.d.pattern, values);
1921
+ }
1922
+ return values;
1923
+ };
1924
+ const addStringLiteralValuesFromPattern = (pattern, values) => {
1925
+ if (pattern.nodeType === 67 /* ParseNodeType.PatternLiteral */) {
1926
+ addStringLiteralValuesFromExpression(pattern.d.expr, values);
1927
+ return;
1928
+ }
1929
+ if (pattern.nodeType === 66 /* ParseNodeType.PatternAs */) {
1930
+ pattern.d.orPatterns.forEach((orPattern) => {
1931
+ addStringLiteralValuesFromPattern(orPattern, values);
1932
+ });
1933
+ }
1934
+ };
1935
+ const addStringLiteralValuesFromExpression = (expr, values) => {
1936
+ if (expr.nodeType === 49 /* ParseNodeType.String */) {
1937
+ values.add(expr.d.value);
1938
+ return;
1939
+ }
1940
+ if (expr.nodeType === 48 /* ParseNodeType.StringList */) {
1941
+ // Be conservative: only treat it as covered if all pieces are plain string literals.
1942
+ if (expr.d.strings.every((s) => s.nodeType === 49 /* ParseNodeType.String */)) {
1943
+ values.add(expr.d.strings.map((s) => s.d.value).join(''));
1944
+ }
1945
+ }
1946
+ };
1947
+ const type = this.evaluator.getType(matchNode.d.expr);
1948
+ if (!type || !(0, typeUtils_1.containsLiteralType)(type)) {
1949
+ return type;
1950
+ }
1951
+ const priorCaseLiteralValues = getPriorCaseStringLiteralValues();
1952
+ if (priorCaseLiteralValues.size === 0) {
1953
+ return type;
1954
+ }
1955
+ const remainingSubtypes = [];
1956
+ (0, typeUtils_1.doForEachSubtype)(type, (subtype) => {
1957
+ if ((0, types_1.isClassInstance)(subtype) &&
1958
+ (0, typeUtils_1.isLiteralType)(subtype) &&
1959
+ types_1.ClassType.isBuiltIn(subtype, 'str') &&
1960
+ typeof subtype.priv.literalValue === 'string' &&
1961
+ priorCaseLiteralValues.has(subtype.priv.literalValue)) {
1962
+ return;
1963
+ }
1964
+ remainingSubtypes.push(subtype);
1965
+ });
1966
+ // If we've filtered everything out, don't offer any redundant literal completions.
1967
+ // Other (non-literal) completion behaviors can still contribute suggestions.
1968
+ return remainingSubtypes.length > 0 ? (0, types_1.combineTypes)(remainingSubtypes) : undefined;
1969
+ }
1796
1970
  _tryAddTypedDictKeys(type, existingKeys, priorWord, priorText, postText, completionMap) {
1797
1971
  let typedDicts = [];
1798
1972
  (0, typeUtils_1.doForEachSubtype)(type, (subtype) => {
@@ -2241,8 +2415,11 @@ class CompletionProvider {
2241
2415
  completionMap.set(completionItem);
2242
2416
  }
2243
2417
  completions.forEach((modulePath, completionName) => {
2418
+ const sortCategory = completionName.startsWith('_')
2419
+ ? SortCategory.PrivateSymbol
2420
+ : SortCategory.ImportModuleName;
2244
2421
  this.addNameToCompletions(completionName, vscode_languageserver_1.CompletionItemKind.Module, '', completionMap, {
2245
- sortText: this._makeSortText(SortCategory.ImportModuleName, completionName),
2422
+ sortText: this._makeSortText(sortCategory, completionName),
2246
2423
  moduleUri: modulePath,
2247
2424
  });
2248
2425
  });