@zzzen/pyright-internal 1.2.0-dev.20261004 → 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 (108) hide show
  1. package/dist/analyzer/binder.js +8 -0
  2. package/dist/analyzer/binder.js.map +1 -1
  3. package/dist/analyzer/checker.d.ts +0 -1
  4. package/dist/analyzer/checker.js +21 -42
  5. package/dist/analyzer/checker.js.map +1 -1
  6. package/dist/analyzer/codeFlowEngine.js +75 -28
  7. package/dist/analyzer/codeFlowEngine.js.map +1 -1
  8. package/dist/analyzer/constraintSolver.js +3 -2
  9. package/dist/analyzer/constraintSolver.js.map +1 -1
  10. package/dist/analyzer/operations.d.ts +2 -0
  11. package/dist/analyzer/operations.js +2 -1
  12. package/dist/analyzer/operations.js.map +1 -1
  13. package/dist/analyzer/overloadResultAdmission.js +115 -3
  14. package/dist/analyzer/overloadResultAdmission.js.map +1 -1
  15. package/dist/analyzer/overloadResultController.js +36 -10
  16. package/dist/analyzer/overloadResultController.js.map +1 -1
  17. package/dist/analyzer/overloadResultSelector.js +32 -12
  18. package/dist/analyzer/overloadResultSelector.js.map +1 -1
  19. package/dist/analyzer/parameterUtils.js +2 -1
  20. package/dist/analyzer/parameterUtils.js.map +1 -1
  21. package/dist/analyzer/parseTreeUtils.d.ts +1 -0
  22. package/dist/analyzer/parseTreeUtils.js +13 -0
  23. package/dist/analyzer/parseTreeUtils.js.map +1 -1
  24. package/dist/analyzer/patternMatching.js +105 -35
  25. package/dist/analyzer/patternMatching.js.map +1 -1
  26. package/dist/analyzer/program.d.ts +3 -0
  27. package/dist/analyzer/program.js +34 -9
  28. package/dist/analyzer/program.js.map +1 -1
  29. package/dist/analyzer/properties.d.ts +2 -2
  30. package/dist/analyzer/properties.js +2 -2
  31. package/dist/analyzer/properties.js.map +1 -1
  32. package/dist/analyzer/protocols.d.ts +3 -1
  33. package/dist/analyzer/protocols.js +24 -2
  34. package/dist/analyzer/protocols.js.map +1 -1
  35. package/dist/analyzer/service.js +6 -2
  36. package/dist/analyzer/service.js.map +1 -1
  37. package/dist/analyzer/sourceEnumerator.d.ts +3 -1
  38. package/dist/analyzer/sourceEnumerator.js +30 -11
  39. package/dist/analyzer/sourceEnumerator.js.map +1 -1
  40. package/dist/analyzer/sourceMapper.d.ts +1 -0
  41. package/dist/analyzer/sourceMapper.js +10 -4
  42. package/dist/analyzer/sourceMapper.js.map +1 -1
  43. package/dist/analyzer/tuples.js +17 -6
  44. package/dist/analyzer/tuples.js.map +1 -1
  45. package/dist/analyzer/typeEvaluator.js +419 -67
  46. package/dist/analyzer/typeEvaluator.js.map +1 -1
  47. package/dist/analyzer/typeEvaluatorTypes.d.ts +2 -1
  48. package/dist/analyzer/typeEvaluatorTypes.js +4 -0
  49. package/dist/analyzer/typeEvaluatorTypes.js.map +1 -1
  50. package/dist/analyzer/typeGuards.d.ts +5 -1
  51. package/dist/analyzer/typeGuards.js +324 -99
  52. package/dist/analyzer/typeGuards.js.map +1 -1
  53. package/dist/analyzer/typePrinter.js +32 -6
  54. package/dist/analyzer/typePrinter.js.map +1 -1
  55. package/dist/analyzer/typeStubRenderer.d.ts +6 -1
  56. package/dist/analyzer/typeStubRenderer.js +19 -12
  57. package/dist/analyzer/typeStubRenderer.js.map +1 -1
  58. package/dist/analyzer/typeUtils.d.ts +1 -0
  59. package/dist/analyzer/typeUtils.js +15 -1
  60. package/dist/analyzer/typeUtils.js.map +1 -1
  61. package/dist/analyzer/typedDicts.d.ts +2 -1
  62. package/dist/analyzer/typedDicts.js +49 -10
  63. package/dist/analyzer/typedDicts.js.map +1 -1
  64. package/dist/analyzer/types.d.ts +2 -1
  65. package/dist/analyzer/types.js +9 -0
  66. package/dist/analyzer/types.js.map +1 -1
  67. package/dist/common/configOptions.d.ts +1 -0
  68. package/dist/common/configOptions.js +9 -0
  69. package/dist/common/configOptions.js.map +1 -1
  70. package/dist/common/windowsProcessTree.json +252 -33
  71. package/dist/tests/cacheManager.test.js +19 -15
  72. package/dist/tests/cacheManager.test.js.map +1 -1
  73. package/dist/tests/checker.test.js +50 -0
  74. package/dist/tests/checker.test.js.map +1 -1
  75. package/dist/tests/config.test.js +126 -0
  76. package/dist/tests/config.test.js.map +1 -1
  77. package/dist/tests/constraintSolver.test.d.ts +1 -0
  78. package/dist/tests/constraintSolver.test.js +39 -0
  79. package/dist/tests/constraintSolver.test.js.map +1 -0
  80. package/dist/tests/fourslash/hover.typedDict.get.fourslash.js +11 -0
  81. package/dist/tests/fourslash/hover.typedDict.get.fourslash.js.map +1 -1
  82. package/dist/tests/fourslash/hover.typedDictUnpacking.dictDisplay.fourslash.d.ts +1 -0
  83. package/dist/tests/fourslash/hover.typedDictUnpacking.dictDisplay.fourslash.js +16 -0
  84. package/dist/tests/fourslash/hover.typedDictUnpacking.dictDisplay.fourslash.js.map +1 -0
  85. package/dist/tests/mypyPrimerAnalysis.test.js +67 -11
  86. package/dist/tests/mypyPrimerAnalysis.test.js.map +1 -1
  87. package/dist/tests/overloadResultController.test.js +379 -1
  88. package/dist/tests/overloadResultController.test.js.map +1 -1
  89. package/dist/tests/signatureHelp.test.js +34 -0
  90. package/dist/tests/signatureHelp.test.js.map +1 -1
  91. package/dist/tests/sourceEnumeratorSymlink.test.js +98 -13
  92. package/dist/tests/sourceEnumeratorSymlink.test.js.map +1 -1
  93. package/dist/tests/sourceMapperUtils.test.js +143 -0
  94. package/dist/tests/sourceMapperUtils.test.js.map +1 -1
  95. package/dist/tests/typeEquality.test.js +85 -2
  96. package/dist/tests/typeEquality.test.js.map +1 -1
  97. package/dist/tests/typeEvaluator1.test.js +47 -3
  98. package/dist/tests/typeEvaluator1.test.js.map +1 -1
  99. package/dist/tests/typeEvaluator3.test.js +23 -0
  100. package/dist/tests/typeEvaluator3.test.js.map +1 -1
  101. package/dist/tests/typeEvaluator5.test.js +1 -1
  102. package/dist/tests/typeEvaluator6.test.js +83 -1
  103. package/dist/tests/typeEvaluator6.test.js.map +1 -1
  104. package/dist/tests/typeEvaluator7.test.js +32 -0
  105. package/dist/tests/typeEvaluator7.test.js.map +1 -1
  106. package/dist/tests/typeEvaluator8.test.js +15 -1
  107. package/dist/tests/typeEvaluator8.test.js.map +1 -1
  108. package/package.json +3 -3
@@ -711,6 +711,368 @@ test('AutomaticOverloadResult exact target and declined controls', () => {
711
711
  enabled.dispose();
712
712
  }
713
713
  });
714
+ test.each(['check-first', 'value-first', 'inline-first', 'projection-first', 'failed-inline-first'])('AutomaticOverloadResult specialized receivers preserve complete witnesses: %s', (order) => {
715
+ const source = (0, testUtils_1.readSampleFile)('overloadResultMethods1.py');
716
+ const automatic = create(source, { automatic: true });
717
+ const normal = create(source, false, 'default', false);
718
+ try {
719
+ const evaluator = automatic.program.evaluator;
720
+ if (order === 'value-first') {
721
+ evaluator.getType(automatic.name('alias', 'assigned', 1));
722
+ }
723
+ else if (order === 'projection-first') {
724
+ evaluator.getType(automatic.name('item', 'projected', 2));
725
+ }
726
+ else if (order === 'failed-inline-first') {
727
+ evaluator.getType(automatic.name('terminal', 'inline', 1));
728
+ }
729
+ else if (order === 'inline-first') {
730
+ const call = automatic.nodes.find((node) => node.nodeType === 9 /* ParseNodeType.Call */ &&
731
+ node.d.leftExpr.nodeType === 35 /* ParseNodeType.MemberAccess */ &&
732
+ node.d.leftExpr.d.member.d.value === 'copy' &&
733
+ (0, parseTreeUtils_1.getEnclosingFunction)(node)?.d.name.d.value === 'inline');
734
+ evaluator.getTypeOfExpression(call);
735
+ }
736
+ const diagnostics = automatic.analyze();
737
+ assert.deepStrictEqual(diagnostics, normal.analyze());
738
+ const expectedErrors = [
739
+ ['ret.accept(3.14)', 'reportArgumentType'],
740
+ ['ret.extend([1, "x"])', 'reportArgumentType'],
741
+ ['invalid: Container[bytes] = ret', 'reportAssignmentType'],
742
+ ['ret.nonexistent_member()', 'reportAttributeAccessIssue'],
743
+ ['unrelated: int = "bad"', 'reportAssignmentType'],
744
+ ['value.copy().accept(3.14)', 'reportArgumentType'],
745
+ ['value.copy().extend([1, "x"])', 'reportArgumentType'],
746
+ ['value.copy().nonexistent_member()', 'reportAttributeAccessIssue'],
747
+ ['value.copy().item().nonexistent_member()', 'reportAttributeAccessIssue'],
748
+ ['terminal.nonexistent_member()', 'reportAttributeAccessIssue'],
749
+ ['item.nonexistent_member()', 'reportAttributeAccessIssue'],
750
+ ['ret.accept(2.5)', 'reportArgumentType'],
751
+ ];
752
+ const errors = diagnostics.filter((d) => d.category === 0 /* DiagnosticCategory.Error */);
753
+ for (const [text, rule] of expectedErrors) {
754
+ const line = source.slice(0, source.indexOf(text)).split('\n').length - 1;
755
+ assert.deepStrictEqual(errors.filter((d) => d.range.start.line === line).map((d) => d.rule), [rule], text);
756
+ }
757
+ assert.equal(errors.length, expectedErrors.length + 3, JSON.stringify(errors.map((d) => [d.range.start.line + 1, d.rule])));
758
+ assert.equal(evaluator.printType(evaluator.getType(automatic.name('alias', 'assigned', 1))), 'OverloadResult[Container[int], Container[str]]');
759
+ assert.equal(evaluator.printType(evaluator.getType(automatic.name('ret', 'reversed_order', 1))), 'OverloadResult[Reversed[str], Reversed[int]]');
760
+ assert.ok(diagnostics.some((d) => d.message === 'Type of "value.copy().item()" is "OverloadResult[int, str]"'));
761
+ assert.equal(evaluator.printType(evaluator.getType(automatic.name('item', 'projected', 2))), 'OverloadResult[int, str]');
762
+ assert.equal(evaluator.printType(evaluator.getType(automatic.name('terminal', 'inline', 1))), 'OverloadResult[str]');
763
+ assert.equal(evaluator.printType(evaluator.getType(automatic.name('ret', 'arguments', 1))), 'OverloadResult[Container[int], Container[str]]');
764
+ assert.ok(diagnostics.some((d) => d.message === 'Type of "value.copy()" is "Original[Any]"'));
765
+ assert.equal(evaluator.printType(evaluator.getType(automatic.name('ret', 'escaped'))), 'Container[int]');
766
+ assert.equal(evaluator.printType(evaluator.getType(automatic.name('ret', 'unknown'))), 'Container[int]');
767
+ assert.deepStrictEqual(automatic.info.getFileInfo(automatic.module).diagnosticSink.fetchAndClear(), []);
768
+ }
769
+ finally {
770
+ automatic.dispose();
771
+ normal.dispose();
772
+ }
773
+ });
774
+ test.each(['check-first', 'reader-first', 'value-first'])('AutomaticOverloadResult inline reader failures preserve native diagnostics: %s', (order) => {
775
+ const definitions = (0, testUtils_1.readSampleFile)('overloadResultMethods1.py').split('\ndef assigned')[0];
776
+ const source = `${definitions}
777
+ from typing import assert_type
778
+ def negative(value: Container[Any], concrete: Container[int]) -> None:
779
+ reveal_type(value.copy().nonexistent_member())
780
+ reveal_type(value.copy().item().nonexistent_member())
781
+ reveal_type(value.copy().accept(3.14))
782
+ assert_type(value.copy().nonexistent_member(), int)
783
+ assert_type(value.copy().item().nonexistent_member(), int)
784
+ assert_type(value.copy().accept(3.14), int)
785
+ reveal_type(concrete.copy().nonexistent_member())
786
+ assert_type(concrete.copy().nonexistent_member(), int)
787
+ def positive(value: Container[Any]) -> None:
788
+ reveal_type(value.copy().item().upper())
789
+ `;
790
+ const automatic = create(source, { automatic: true });
791
+ const ordinary = create(source, false);
792
+ try {
793
+ const evaluator = automatic.program.evaluator;
794
+ const reader = automatic.nodes.find((node) => node.nodeType === 9 /* ParseNodeType.Call */ &&
795
+ node.d.leftExpr.nodeType === 38 /* ParseNodeType.Name */ &&
796
+ node.d.leftExpr.d.value === 'reveal_type' &&
797
+ (0, parseTreeUtils_1.getEnclosingFunction)(node)?.d.name.d.value === 'negative');
798
+ if (order !== 'check-first') {
799
+ const node = order === 'reader-first' ? reader : reader.d.args[0].d.valueExpr;
800
+ evaluator.getTypeOfExpression(node);
801
+ evaluator.getTypeOfExpression(node);
802
+ }
803
+ const diagnostics = automatic.analyze();
804
+ const positiveLine = source.slice(0, source.indexOf('def positive')).split('\n').length - 1;
805
+ assert.deepStrictEqual(diagnostics.filter((d) => d.range.start.line < positiveLine), ordinary.analyze().filter((d) => d.range.start.line < positiveLine));
806
+ for (const [text, rule] of [
807
+ ['value.copy().nonexistent_member()', 'reportAttributeAccessIssue'],
808
+ ['value.copy().item().nonexistent_member()', 'reportAttributeAccessIssue'],
809
+ ['value.copy().accept(3.14)', 'reportArgumentType'],
810
+ ]) {
811
+ for (const readerName of ['reveal_type', 'assert_type']) {
812
+ const line = source.slice(0, source.indexOf(`${readerName}(${text}`)).split('\n').length - 1;
813
+ assert.deepStrictEqual(diagnostics
814
+ .filter((d) => d.category === 0 /* DiagnosticCategory.Error */ && d.range.start.line === line)
815
+ .map((d) => d.rule)
816
+ .sort(), (readerName === 'assert_type' ? [rule, 'reportAssertTypeFailure'] : [rule]).sort());
817
+ }
818
+ }
819
+ assert.ok(diagnostics.some((d) => d.message === 'Type of "value.copy().item().upper()" is "OverloadResult[str]"'));
820
+ assert.equal(diagnostics.filter((d) => d.category === 0 /* DiagnosticCategory.Error */ && d.range.start.line >= positiveLine)
821
+ .length, 0);
822
+ assert.deepStrictEqual(automatic.info.getFileInfo(automatic.module).diagnosticSink.fetchAndClear(), []);
823
+ }
824
+ finally {
825
+ automatic.dispose();
826
+ ordinary.dispose();
827
+ }
828
+ });
829
+ test.each([
830
+ { inline: false, unused: false, gradual: false },
831
+ { inline: false, unused: true, gradual: false },
832
+ { inline: false, unused: true, gradual: true },
833
+ { inline: true, unused: false, gradual: false },
834
+ { inline: true, unused: true, gradual: false },
835
+ { inline: true, unused: true, gradual: true },
836
+ ])('AutomaticOverloadResult stored projections require untransformed receiver declarations: %j', (shape) => {
837
+ const source = `from typing import Any, Generic, TypeVar, overload, reveal_type
838
+ T = TypeVar("T")
839
+ class Projected(Generic[T]):
840
+ def item(self) -> ${shape.gradual ? 'Any' : 'T'}:
841
+ raise NotImplementedError
842
+ class Container(Generic[T]):
843
+ @overload
844
+ def copy(self: "Container[int]") -> "Container[int]": ...
845
+ @overload
846
+ def copy(self: "Container[str]") -> "Container[str]": ...
847
+ def copy(self) -> "Container[Any]":
848
+ return self
849
+ def project(self) -> Projected[T]:
850
+ raise NotImplementedError
851
+ ${shape.unused ? ' def item(self) -> int:\n raise NotImplementedError' : ''}
852
+ def positive(value: Container[Any]) -> None:
853
+ ret = value.copy()${shape.inline ? '.project()' : ''}
854
+ alias = ret
855
+ projected = alias${shape.inline ? '' : '.project()'}
856
+ projected_alias = projected
857
+ item = projected_alias.item()
858
+ reveal_type(ret)
859
+ reveal_type(projected)
860
+ reveal_type(item)
861
+ item.upper()
862
+ item.nonexistent_member()
863
+ `;
864
+ const automatic = create(source, { automatic: true });
865
+ const ordinary = create(source, false);
866
+ try {
867
+ assert.deepStrictEqual(automatic.analyze(), ordinary.analyze());
868
+ const evaluator = automatic.program.evaluator;
869
+ assert.equal(evaluator.printType(evaluator.getType(automatic.name('item', 'positive', 2))), shape.gradual ? 'Any' : 'int');
870
+ assert.equal(automatic.program.experimentalOverloadResultController.getAutomaticStats().selected, 0);
871
+ assert.deepStrictEqual(automatic.info.getFileInfo(automatic.module).diagnosticSink.fetchAndClear(), []);
872
+ }
873
+ finally {
874
+ automatic.dispose();
875
+ ordinary.dispose();
876
+ }
877
+ });
878
+ test('AutomaticOverloadResult stored projections preserve Name-only receiver aliases', () => {
879
+ const definitions = (0, testUtils_1.readSampleFile)('overloadResultMethods1.py').split('\ndef assigned')[0];
880
+ const source = `${definitions}
881
+ def positive(value: Container[Any]) -> None:
882
+ ret = value.copy()
883
+ first = ret
884
+ second = first
885
+ item = second.item()
886
+ reveal_type(item)
887
+ item.upper()
888
+ item.bit_length()
889
+ item.nonexistent_member()
890
+ `;
891
+ const automatic = create(source, { automatic: true });
892
+ try {
893
+ const diagnostics = automatic.analyze();
894
+ const evaluator = automatic.program.evaluator;
895
+ assert.equal(evaluator.printType(evaluator.getType(automatic.name('item', 'positive', 2))), 'OverloadResult[int, str]');
896
+ const errors = diagnostics.filter((d) => d.category === 0 /* DiagnosticCategory.Error */);
897
+ assert.deepStrictEqual(errors.map((d) => d.rule), ['reportAttributeAccessIssue']);
898
+ assert.equal(errors[0].range.start.line, source.slice(0, source.indexOf('item.nonexistent_member()')).split('\n').length - 1);
899
+ assert.deepStrictEqual(automatic.info.getFileInfo(automatic.module).diagnosticSink.fetchAndClear(), []);
900
+ }
901
+ finally {
902
+ automatic.dispose();
903
+ }
904
+ });
905
+ test('AutomaticOverloadResult inline readers avoid duplicate ordinary evaluation', () => {
906
+ const definitions = (0, testUtils_1.readSampleFile)('overloadResultMethods1.py').split('\ndef assigned')[0];
907
+ const source = `${definitions}
908
+ def positive(value: Container[Any]) -> None:
909
+ reveal_type(value.copy().item().upper())
910
+ `;
911
+ const automatic = create(source, { automatic: true });
912
+ try {
913
+ const reader = automatic.nodes.find((node) => node.nodeType === 9 /* ParseNodeType.Call */ &&
914
+ node.d.leftExpr.nodeType === 38 /* ParseNodeType.Name */ &&
915
+ node.d.leftExpr.d.value === 'reveal_type');
916
+ const root = reader.parent;
917
+ const evaluator = automatic.program.evaluator;
918
+ for (let round = 0; round < 2; round++) {
919
+ assert.equal(evaluator.printType(evaluator.getTypeOfExpression(reader).type), 'OverloadResult[str]');
920
+ }
921
+ const trials = automatic.events.filter((event) => event.kind === 'trial' && event.root === root);
922
+ assert.deepStrictEqual(trials.map((event) => event.kind === 'trial' && event.mode), ['reader']);
923
+ const diagnostics = automatic.analyze();
924
+ assert.equal(diagnostics.filter((d) => d.category === 0 /* DiagnosticCategory.Error */).length, 0);
925
+ assert.deepStrictEqual(automatic.info.getFileInfo(automatic.module).diagnosticSink.fetchAndClear(), []);
926
+ }
927
+ finally {
928
+ automatic.dispose();
929
+ }
930
+ });
931
+ test.each([{ candidates: 1 }, { calls: 0 }, { proofUnits: 0 }, { rootNodes: 1 }])('AutomaticOverloadResult specialized receiver cutoffs retain ordinary contracts: %j', (limits) => {
932
+ const source = (0, testUtils_1.readSampleFile)('overloadResultMethods1.py');
933
+ const ordinary = create(source, false);
934
+ const limited = create(source, { automatic: true, limits });
935
+ try {
936
+ assert.deepStrictEqual(limited.analyze(), ordinary.analyze());
937
+ const evaluator = limited.program.evaluator;
938
+ for (const fn of ['assigned', 'reversed_order', 'escaped', 'unknown']) {
939
+ assert.deepStrictEqual(resultSummary(evaluator, evaluator.getTypeOfExpression(limited.name('ret', fn))), resultSummary(ordinary.program.evaluator, ordinary.program.evaluator.getTypeOfExpression(ordinary.name('ret', fn))));
940
+ }
941
+ assert.deepStrictEqual(limited.info.getFileInfo(limited.module).diagnosticSink.fetchAndClear(), []);
942
+ }
943
+ finally {
944
+ ordinary.dispose();
945
+ limited.dispose();
946
+ }
947
+ });
948
+ test('AutomaticOverloadResult specialized receiver cancellation restores inline discovery', () => {
949
+ const source = (0, testUtils_1.readSampleFile)('overloadResultMethods1.py');
950
+ const reference = create(source, { automatic: true });
951
+ let fault = true;
952
+ const test = create(source, {
953
+ automatic: true,
954
+ observe(event) {
955
+ if (fault && event.kind === 'beforeCall' && event.mode === 'candidate') {
956
+ fault = false;
957
+ throw new cancellationUtils_1.OperationCanceledException();
958
+ }
959
+ },
960
+ });
961
+ try {
962
+ const call = test.nodes.find((node) => node.nodeType === 9 /* ParseNodeType.Call */ &&
963
+ node.d.leftExpr.nodeType === 35 /* ParseNodeType.MemberAccess */ &&
964
+ node.d.leftExpr.d.member.d.value === 'copy' &&
965
+ (0, parseTreeUtils_1.getEnclosingFunction)(node)?.d.name.d.value === 'inline');
966
+ const evaluator = test.program.evaluator;
967
+ assert.throws(() => evaluator.getTypeOfExpression(call), (error) => cancellationUtils_1.OperationCanceledException.is(error));
968
+ assert.equal(evaluator.isSpeculativeModeInUse(undefined), false);
969
+ assert.deepStrictEqual(test.info.getFileInfo(test.module).diagnosticSink.fetchAndClear(), []);
970
+ assert.ok((0, types_1.isOverloadResult)(evaluator.getTypeOfExpression(call).type));
971
+ assert.deepStrictEqual(test.analyze(), reference.analyze());
972
+ assert.ok(test.program.experimentalOverloadResultController.getStats(test.module).retryReservations > 0);
973
+ }
974
+ finally {
975
+ reference.dispose();
976
+ test.dispose();
977
+ }
978
+ });
979
+ test('AutomaticOverloadResult specialized receivers preserve warm queries across file replacement', () => {
980
+ const source = (0, testUtils_1.readSampleFile)('overloadResultMethods1.py');
981
+ const test = create(source, { automatic: true });
982
+ try {
983
+ for (const [version, text] of [source, source.replace(/\bstr\b/g, 'bytes'), source].entries()) {
984
+ if (version) {
985
+ test.program.setFileOpened(test.uri, version + 1, text);
986
+ test.program.getBoundSourceFile(test.uri);
987
+ }
988
+ const reference = create(text, { automatic: true });
989
+ try {
990
+ assert.deepStrictEqual(test.analyze(), reference.analyze());
991
+ const nodes = new Nodes();
992
+ nodes.walk(test.program.getParseResults(test.uri).parserOutput.parseTree);
993
+ const alias = nodes.nodes.find((node) => node.nodeType === 38 /* ParseNodeType.Name */ &&
994
+ node.d.value === 'alias' &&
995
+ (0, parseTreeUtils_1.getEnclosingFunction)(node)?.d.name.d.value === 'assigned');
996
+ const evaluator = test.program.evaluator;
997
+ const expected = resultSummary(reference.program.evaluator, reference.program.evaluator.getTypeResult(reference.name('alias', 'assigned')));
998
+ for (let round = 0; round < 3; round++) {
999
+ assert.deepStrictEqual(resultSummary(evaluator, evaluator.getTypeResult(alias)), expected);
1000
+ assert.deepStrictEqual(resultSummary(evaluator, evaluator.getTypeOfExpression(alias, 2 /* EvalFlags.NoSpecialize */)), expected);
1001
+ }
1002
+ const module = test.program.getParseResults(test.uri).parserOutput.parseTree;
1003
+ assert.deepStrictEqual(test.info.getFileInfo(module).diagnosticSink.fetchAndClear(), []);
1004
+ assert.deepStrictEqual(test.analyze(), reference.analyze());
1005
+ }
1006
+ finally {
1007
+ reference.dispose();
1008
+ }
1009
+ }
1010
+ }
1011
+ finally {
1012
+ test.dispose();
1013
+ }
1014
+ });
1015
+ test.each([
1016
+ ' values = [value.copy()]',
1017
+ ' consume(value.copy())',
1018
+ ' value.copy().accept(other.copy().item())',
1019
+ ' assert_type(1, value.copy())',
1020
+ ' method = value.copy\n ret = method()\n ret.item().upper()',
1021
+ ' if flag:\n ret = value.copy()\n ret.item().upper()',
1022
+ ])('AutomaticOverloadResult unsupported receiver uses remain ordinary: %s', (body) => {
1023
+ const definitions = (0, testUtils_1.readSampleFile)('overloadResultMethods1.py').split('\ndef assigned')[0];
1024
+ const source = `${definitions}
1025
+ from typing import assert_type
1026
+ def consume(value: Container[Any]) -> None: ...
1027
+ def positive(value: Container[Any], other: Container[Any], flag: bool) -> None:
1028
+ ${body}
1029
+ `;
1030
+ const ordinary = create(source, false);
1031
+ const automatic = create(source, { automatic: true });
1032
+ try {
1033
+ assert.deepStrictEqual(automatic.analyze(), ordinary.analyze());
1034
+ assert.equal(automatic.program.experimentalOverloadResultController.getAutomaticStats().selected, 0);
1035
+ assert.deepStrictEqual(automatic.info.getFileInfo(automatic.module).diagnosticSink.fetchAndClear(), []);
1036
+ }
1037
+ finally {
1038
+ ordinary.dispose();
1039
+ automatic.dispose();
1040
+ }
1041
+ });
1042
+ test.each([
1043
+ { parameters: ', flag: int = 0', arguments: '', variance: '', receiver: 'Container[Any]' },
1044
+ { parameters: ', flag: int', arguments: 'flag=flag', variance: '', receiver: 'Container[Any]' },
1045
+ { parameters: '', arguments: '', variance: ', covariant=True', receiver: 'Container[Any]' },
1046
+ { parameters: '', arguments: '', variance: '', receiver: 'Child[Any]' },
1047
+ ])('AutomaticOverloadResult unsupported receiver signatures retain their metadata: %j', (shape) => {
1048
+ const source = `from typing import Any, Generic, TypeVar, overload, reveal_type
1049
+ T = TypeVar("T"${shape.variance})
1050
+ class Container(Generic[T]):
1051
+ @overload
1052
+ def copy(self: "Container[int]"${shape.parameters}) -> "Container[int]": ...
1053
+ @overload
1054
+ def copy(self: "Container[str]"${shape.parameters}) -> "Container[str]": ...
1055
+ def copy(self${shape.parameters}) -> "Container[Any]":
1056
+ return self
1057
+ class Child(Container[T]):
1058
+ pass
1059
+ def positive(value: ${shape.receiver}, flag: int) -> None:
1060
+ ret = value.copy(${shape.arguments})
1061
+ reveal_type(ret)
1062
+ ret.nonexistent_member()
1063
+ `;
1064
+ const ordinary = create(source, false);
1065
+ const automatic = create(source, { automatic: true });
1066
+ try {
1067
+ assert.deepStrictEqual(automatic.analyze(), ordinary.analyze());
1068
+ assert.deepStrictEqual(resultSummary(automatic.program.evaluator, automatic.program.evaluator.getTypeOfExpression(automatic.name('ret'))), resultSummary(ordinary.program.evaluator, ordinary.program.evaluator.getTypeOfExpression(ordinary.name('ret'))));
1069
+ assert.equal(automatic.program.experimentalOverloadResultController.getAutomaticStats().selected, 0);
1070
+ }
1071
+ finally {
1072
+ ordinary.dispose();
1073
+ automatic.dispose();
1074
+ }
1075
+ });
714
1076
  test('AutomaticOverloadResult re-enables the explicit-off internal Program control without injected seeds', () => {
715
1077
  const test = create((0, testUtils_1.readSampleFile)('overloadResultAutomatic1.py'), false);
716
1078
  try {
@@ -1471,13 +1833,29 @@ def positive(value: list[Any]):
1471
1833
  automatic.dispose();
1472
1834
  }
1473
1835
  });
1836
+ test('AutomaticOverloadResult changes only the supported specialized receiver in overloadCall6.py', () => {
1837
+ const source = (0, testUtils_1.readSampleFile)('overloadCall6.py');
1838
+ const resultType = 'OverloadResult[ClassA[int], ClassA[str]]';
1839
+ const ordinary = create(source.replace(`expected_text="${resultType}"`, 'expected_text="ClassA[int]"'), false);
1840
+ const automatic = create(source, { automatic: true });
1841
+ try {
1842
+ const expected = ordinary.analyze();
1843
+ const changed = expected.filter((d) => d.message === 'Type of "a.m1()" is "ClassA[int]"');
1844
+ assert.equal(changed.length, 1);
1845
+ assert.deepStrictEqual(automatic.analyze(), expected.map((d) => (d === changed[0] ? { ...d, message: `Type of "a.m1()" is "${resultType}"` } : d)));
1846
+ assert.equal(automatic.program.experimentalOverloadResultController.getAutomaticStats().selected, 1);
1847
+ }
1848
+ finally {
1849
+ ordinary.dispose();
1850
+ automatic.dispose();
1851
+ }
1852
+ });
1474
1853
  test.each([
1475
1854
  'constructor12.py',
1476
1855
  'constructor34.py',
1477
1856
  'protocol54.py',
1478
1857
  'typeVarDefaultClass5.py',
1479
1858
  'typeVarDefaultClass6.py',
1480
- 'overloadCall6.py',
1481
1859
  'overloadCall12.py',
1482
1860
  ])('AutomaticOverloadResult preserves complete ordinary source diagnostics for %s', (sample) => {
1483
1861
  const source = (0, testUtils_1.readSampleFile)(sample);