@zzzen/pyright-internal 1.2.0-dev.20261018 → 1.2.0-dev.20261108
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.
- package/dist/analyzer/binder.js +29 -12
- package/dist/analyzer/binder.js.map +1 -1
- package/dist/analyzer/checker.js +4 -0
- package/dist/analyzer/checker.js.map +1 -1
- package/dist/analyzer/codeFlowEngine.js +3 -3
- package/dist/analyzer/codeFlowEngine.js.map +1 -1
- package/dist/analyzer/constructorTransform.js +12 -0
- package/dist/analyzer/constructorTransform.js.map +1 -1
- package/dist/analyzer/constructors.d.ts +1 -1
- package/dist/analyzer/constructors.js +1 -1
- package/dist/analyzer/constructors.js.map +1 -1
- package/dist/analyzer/dataClasses.js +14 -5
- package/dist/analyzer/dataClasses.js.map +1 -1
- package/dist/analyzer/decorators.d.ts +2 -2
- package/dist/analyzer/decorators.js +22 -2
- package/dist/analyzer/decorators.js.map +1 -1
- package/dist/analyzer/functionTransform.d.ts +5 -0
- package/dist/analyzer/functionTransform.js +6 -3
- package/dist/analyzer/functionTransform.js.map +1 -1
- package/dist/analyzer/missingBindingMetadata.d.ts +6 -0
- package/dist/analyzer/missingBindingMetadata.js +22 -0
- package/dist/analyzer/missingBindingMetadata.js.map +1 -0
- package/dist/analyzer/namedTuples.d.ts +5 -1
- package/dist/analyzer/namedTuples.js +64 -35
- package/dist/analyzer/namedTuples.js.map +1 -1
- package/dist/analyzer/operations.js +45 -1
- package/dist/analyzer/operations.js.map +1 -1
- package/dist/analyzer/parseTreeUtils.d.ts +2 -0
- package/dist/analyzer/parseTreeUtils.js +43 -0
- package/dist/analyzer/parseTreeUtils.js.map +1 -1
- package/dist/analyzer/patternMatching.d.ts +5 -1
- package/dist/analyzer/patternMatching.js +6 -1
- package/dist/analyzer/patternMatching.js.map +1 -1
- package/dist/analyzer/program.d.ts +3 -0
- package/dist/analyzer/program.js +71 -1
- package/dist/analyzer/program.js.map +1 -1
- package/dist/analyzer/sentinel.js +7 -1
- package/dist/analyzer/sentinel.js.map +1 -1
- package/dist/analyzer/sourceFile.js +13 -6
- package/dist/analyzer/sourceFile.js.map +1 -1
- package/dist/analyzer/tupleComparison.d.ts +6 -0
- package/dist/analyzer/tupleComparison.js +731 -0
- package/dist/analyzer/tupleComparison.js.map +1 -0
- package/dist/analyzer/tuples.d.ts +1 -1
- package/dist/analyzer/tuples.js +35 -4
- package/dist/analyzer/tuples.js.map +1 -1
- package/dist/analyzer/typeCacheUtils.d.ts +1 -0
- package/dist/analyzer/typeCacheUtils.js +10 -0
- package/dist/analyzer/typeCacheUtils.js.map +1 -1
- package/dist/analyzer/typeEvaluator/boundMethodSpecialization.d.ts +15 -0
- package/dist/analyzer/typeEvaluator/boundMethodSpecialization.js +98 -0
- package/dist/analyzer/typeEvaluator/boundMethodSpecialization.js.map +1 -0
- package/dist/analyzer/typeEvaluator/classConstruction.d.ts +25 -0
- package/dist/analyzer/typeEvaluator/classConstruction.js +251 -0
- package/dist/analyzer/typeEvaluator/classConstruction.js.map +1 -0
- package/dist/analyzer/typeEvaluator/collectionInference.d.ts +41 -0
- package/dist/analyzer/typeEvaluator/collectionInference.js +695 -0
- package/dist/analyzer/typeEvaluator/collectionInference.js.map +1 -0
- package/dist/analyzer/typeEvaluator/diagnostics.d.ts +33 -0
- package/dist/analyzer/typeEvaluator/diagnostics.js +198 -0
- package/dist/analyzer/typeEvaluator/diagnostics.js.map +1 -0
- package/dist/analyzer/typeEvaluator/evaluatorCore.d.ts +80 -0
- package/dist/analyzer/typeEvaluator/evaluatorCore.js +1126 -0
- package/dist/analyzer/typeEvaluator/evaluatorCore.js.map +1 -0
- package/dist/analyzer/typeEvaluator/evaluatorNarrowing.d.ts +17 -0
- package/dist/analyzer/typeEvaluator/evaluatorNarrowing.js +370 -0
- package/dist/analyzer/typeEvaluator/evaluatorNarrowing.js.map +1 -0
- package/dist/analyzer/typeEvaluator/expressionEvaluation.d.ts +81 -0
- package/dist/analyzer/typeEvaluator/expressionEvaluation.js +1802 -0
- package/dist/analyzer/typeEvaluator/expressionEvaluation.js.map +1 -0
- package/dist/analyzer/typeEvaluator/flowAnalysis.d.ts +33 -0
- package/dist/analyzer/typeEvaluator/flowAnalysis.js +217 -0
- package/dist/analyzer/typeEvaluator/flowAnalysis.js.map +1 -0
- package/dist/analyzer/typeEvaluator/internals.d.ts +137 -0
- package/dist/analyzer/typeEvaluator/internals.js +10 -0
- package/dist/analyzer/typeEvaluator/internals.js.map +1 -0
- package/dist/analyzer/typeEvaluator/literalTypes.d.ts +3 -0
- package/dist/analyzer/typeEvaluator/literalTypes.js +52 -0
- package/dist/analyzer/typeEvaluator/literalTypes.js.map +1 -0
- package/dist/analyzer/typeEvaluator/memberResolution.d.ts +79 -0
- package/dist/analyzer/typeEvaluator/memberResolution.js +1007 -0
- package/dist/analyzer/typeEvaluator/memberResolution.js.map +1 -0
- package/dist/analyzer/typeEvaluator/overrideValidation.d.ts +15 -0
- package/dist/analyzer/typeEvaluator/overrideValidation.js +422 -0
- package/dist/analyzer/typeEvaluator/overrideValidation.js.map +1 -0
- package/dist/analyzer/typeEvaluator/returnTypeInference.d.ts +33 -0
- package/dist/analyzer/typeEvaluator/returnTypeInference.js +226 -0
- package/dist/analyzer/typeEvaluator/returnTypeInference.js.map +1 -0
- package/dist/analyzer/typeEvaluator/specialFormCreation.d.ts +39 -0
- package/dist/analyzer/typeEvaluator/specialFormCreation.js +1728 -0
- package/dist/analyzer/typeEvaluator/specialFormCreation.js.map +1 -0
- package/dist/analyzer/typeEvaluator/tupleUnpacking.d.ts +2 -0
- package/dist/analyzer/typeEvaluator/tupleUnpacking.js +36 -0
- package/dist/analyzer/typeEvaluator/tupleUnpacking.js.map +1 -0
- package/dist/analyzer/typeEvaluator/typeCompatibility.d.ts +36 -0
- package/dist/analyzer/typeEvaluator/typeCompatibility.js +1320 -0
- package/dist/analyzer/typeEvaluator/typeCompatibility.js.map +1 -0
- package/dist/analyzer/typeEvaluator/typeGuardNarrowing.d.ts +186 -0
- package/dist/analyzer/typeEvaluator/typeGuardNarrowing.js +1683 -0
- package/dist/analyzer/typeEvaluator/typeGuardNarrowing.js.map +1 -0
- package/dist/analyzer/typeEvaluator/typeVarHandling.d.ts +48 -0
- package/dist/analyzer/typeEvaluator/typeVarHandling.js +756 -0
- package/dist/analyzer/typeEvaluator/typeVarHandling.js.map +1 -0
- package/dist/analyzer/typeEvaluator.d.ts +3 -31
- package/dist/analyzer/typeEvaluator.js +5140 -13656
- package/dist/analyzer/typeEvaluator.js.map +1 -1
- package/dist/analyzer/typeEvaluatorTypes.d.ts +1 -1
- package/dist/analyzer/typeEvaluatorTypes.js +2 -3
- package/dist/analyzer/typeEvaluatorTypes.js.map +1 -1
- package/dist/analyzer/typeGuards.d.ts +3 -2
- package/dist/analyzer/typeGuards.js +236 -1375
- package/dist/analyzer/typeGuards.js.map +1 -1
- package/dist/analyzer/typeUtils.js +9 -2
- package/dist/analyzer/typeUtils.js.map +1 -1
- package/dist/analyzer/typedDicts.js +111 -0
- package/dist/analyzer/typedDicts.js.map +1 -1
- package/dist/analyzer/types.d.ts +14 -0
- package/dist/analyzer/types.js +215 -10
- package/dist/analyzer/types.js.map +1 -1
- package/dist/browser/browserConnection.d.ts +12 -0
- package/dist/browser/browserConnection.js +23 -0
- package/dist/browser/browserConnection.js.map +1 -0
- package/dist/browser/browserFileSystem.d.ts +73 -0
- package/dist/browser/browserFileSystem.js +578 -0
- package/dist/browser/browserFileSystem.js.map +1 -0
- package/dist/browser/browserHost.d.ts +4 -0
- package/dist/browser/browserHost.js +10 -0
- package/dist/browser/browserHost.js.map +1 -0
- package/dist/browser/browserProcess.d.ts +1 -0
- package/dist/browser/browserProcess.js +17 -0
- package/dist/browser/browserProcess.js.map +1 -0
- package/dist/browser/browserServer.d.ts +8 -0
- package/dist/browser/browserServer.js +32 -0
- package/dist/browser/browserServer.js.map +1 -0
- package/dist/browser/cancellation/common.d.ts +10 -0
- package/dist/browser/cancellation/common.js +114 -0
- package/dist/browser/cancellation/common.js.map +1 -0
- package/dist/browser/cancellation/objectURLReceiverStrategy.d.ts +5 -0
- package/dist/browser/cancellation/objectURLReceiverStrategy.js +37 -0
- package/dist/browser/cancellation/objectURLReceiverStrategy.js.map +1 -0
- package/dist/browser/cancellation/objectURLSenderStrategy.d.ts +7 -0
- package/dist/browser/cancellation/objectURLSenderStrategy.js +32 -0
- package/dist/browser/cancellation/objectURLSenderStrategy.js.map +1 -0
- package/dist/browser/worker.d.ts +1 -0
- package/dist/browser/worker.js +33 -0
- package/dist/browser/worker.js.map +1 -0
- package/dist/common/processUtils.d.ts +6 -0
- package/dist/common/processUtils.js +56 -1
- package/dist/common/processUtils.js.map +1 -1
- package/dist/common/textEditTracker.js +1 -1
- package/dist/common/textEditTracker.js.map +1 -1
- package/dist/common/windowsProcessTree.d.ts +2 -0
- package/dist/common/windowsProcessTree.js +23 -0
- package/dist/common/windowsProcessTree.js.map +1 -1
- package/dist/common/windowsProcessTree.json +23 -3
- package/dist/languageServerBase.d.ts +3 -0
- package/dist/languageServerBase.js +44 -12
- package/dist/languageServerBase.js.map +1 -1
- package/dist/languageService/callHierarchyProvider.js +6 -6
- package/dist/languageService/callHierarchyProvider.js.map +1 -1
- package/dist/languageService/referencesProvider.js +3 -3
- package/dist/languageService/referencesProvider.js.map +1 -1
- package/dist/languageService/renameProvider.js +1 -1
- package/dist/languageService/renameProvider.js.map +1 -1
- package/dist/languageService/symbolIndexer.js +2 -2
- package/dist/languageService/symbolIndexer.js.map +1 -1
- package/dist/localization/localize.d.ts +2 -0
- package/dist/localization/localize.js +2 -0
- package/dist/localization/localize.js.map +1 -1
- package/dist/localization/package.nls.en-us.json +8 -0
- package/dist/parser/parseTreeTokenReuse.d.ts +34 -0
- package/dist/parser/parseTreeTokenReuse.js +897 -0
- package/dist/parser/parseTreeTokenReuse.js.map +1 -0
- package/dist/parser/tokenizer.d.ts +10 -1
- package/dist/parser/tokenizer.js +184 -130
- package/dist/parser/tokenizer.js.map +1 -1
- package/dist/pyrightServer.d.ts +34 -0
- package/dist/pyrightServer.js +239 -0
- package/dist/pyrightServer.js.map +1 -0
- package/dist/server.d.ts +3 -23
- package/dist/server.js +12 -232
- package/dist/server.js.map +1 -1
- package/dist/tests/benchmarks/typeInferenceComparison.d.ts +1 -0
- package/dist/tests/benchmarks/typeInferenceComparison.js +1235 -0
- package/dist/tests/benchmarks/typeInferenceComparison.js.map +1 -0
- package/dist/tests/benchmarks/typeInferencePyrightEntry.d.ts +1 -0
- package/dist/tests/benchmarks/typeInferencePyrightEntry.js +53 -0
- package/dist/tests/benchmarks/typeInferencePyrightEntry.js.map +1 -0
- package/dist/tests/browserCancellation.test.d.ts +1 -0
- package/dist/tests/browserCancellation.test.js +63 -0
- package/dist/tests/browserCancellation.test.js.map +1 -0
- package/dist/tests/browserServer.test.d.ts +1 -0
- package/dist/tests/browserServer.test.js +177 -0
- package/dist/tests/browserServer.test.js.map +1 -0
- package/dist/tests/checker.test.js +8 -0
- package/dist/tests/checker.test.js.map +1 -1
- package/dist/tests/constraintSolver.test.js +45 -0
- package/dist/tests/constraintSolver.test.js.map +1 -1
- package/dist/tests/fourSlashParser.test.js +35 -0
- package/dist/tests/fourSlashParser.test.js.map +1 -1
- package/dist/tests/harness/fourslash/fourSlashParser.js +14 -4
- package/dist/tests/harness/fourslash/fourSlashParser.js.map +1 -1
- package/dist/tests/languageServer.test.js +15 -0
- package/dist/tests/languageServer.test.js.map +1 -1
- package/dist/tests/lsp/languageServer.js +6 -6
- package/dist/tests/lsp/languageServer.js.map +1 -1
- package/dist/tests/mypyPrimerAnalysis.test.js +148 -1
- package/dist/tests/mypyPrimerAnalysis.test.js.map +1 -1
- package/dist/tests/typeCacheUtils.test.js +46 -0
- package/dist/tests/typeCacheUtils.test.js.map +1 -1
- package/dist/tests/typeEvaluator1.test.js +78 -1
- package/dist/tests/typeEvaluator1.test.js.map +1 -1
- package/dist/tests/typeEvaluator2.test.js +54 -1
- package/dist/tests/typeEvaluator2.test.js.map +1 -1
- package/dist/tests/typeEvaluator3.test.js +4 -0
- package/dist/tests/typeEvaluator3.test.js.map +1 -1
- package/dist/tests/typeEvaluator4.test.js +42 -3
- package/dist/tests/typeEvaluator4.test.js.map +1 -1
- package/dist/tests/typeEvaluator6.test.js +35 -0
- package/dist/tests/typeEvaluator6.test.js.map +1 -1
- package/dist/tests/typeEvaluator7.test.js +414 -0
- package/dist/tests/typeEvaluator7.test.js.map +1 -1
- package/dist/tests/typeEvaluator8.test.js +1291 -1
- package/dist/tests/typeEvaluator8.test.js.map +1 -1
- package/dist/tests/typeUtils.test.js +28 -0
- package/dist/tests/typeUtils.test.js.map +1 -1
- package/dist/tests/types.test.js +55 -0
- package/dist/tests/types.test.js.map +1 -1
- package/dist/typeServer/programWrapper.js +8 -2
- package/dist/typeServer/programWrapper.js.map +1 -1
- package/dist/typeServer/server.d.ts +12 -2
- package/dist/typeServer/server.js +97 -0
- package/dist/typeServer/server.js.map +1 -1
- package/dist/typeServer/stubGenerator.js +136 -3
- package/dist/typeServer/stubGenerator.js.map +1 -1
- package/dist/typeServer/typeServerConversionUtils.js +13 -0
- package/dist/typeServer/typeServerConversionUtils.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,731 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* tupleComparison.ts
|
|
4
|
+
* Copyright (c) Microsoft Corporation.
|
|
5
|
+
* Licensed under the MIT license.
|
|
6
|
+
*
|
|
7
|
+
* Operation-local views for lexicographic tuple comparison.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.isTupleOrdering = isTupleOrdering;
|
|
11
|
+
exports.getTupleComparisonResult = getTupleComparisonResult;
|
|
12
|
+
const parseTreeUtils_1 = require("./parseTreeUtils");
|
|
13
|
+
const typeUtils_1 = require("./typeUtils");
|
|
14
|
+
const types_1 = require("./types");
|
|
15
|
+
const comparisonMethods = {
|
|
16
|
+
[20 /* OperatorType.LessThan */]: ['__lt__', '__gt__'],
|
|
17
|
+
[21 /* OperatorType.LessThanOrEqual */]: ['__le__', '__ge__'],
|
|
18
|
+
[15 /* OperatorType.GreaterThan */]: ['__gt__', '__lt__'],
|
|
19
|
+
[16 /* OperatorType.GreaterThanOrEqual */]: ['__ge__', '__le__'],
|
|
20
|
+
};
|
|
21
|
+
function isTupleOrdering(operator) {
|
|
22
|
+
return comparisonMethods[operator] !== undefined;
|
|
23
|
+
}
|
|
24
|
+
function getTupleComparisonResult(evaluator, leftType, rightType, operator, errorNode) {
|
|
25
|
+
const type = inferTupleComparison(evaluator, leftType, rightType, operator, errorNode);
|
|
26
|
+
return type ? { type } : undefined;
|
|
27
|
+
}
|
|
28
|
+
// Validate lexicographic ordering without changing either operand's narrowed
|
|
29
|
+
// type. Memoize repeated type pairs and visit each alignment only once.
|
|
30
|
+
function inferTupleComparison(evaluator, leftType, rightType, operator, errorNode) {
|
|
31
|
+
const leftExpression = errorNode.nodeType === 7 /* ParseNodeType.BinaryOperation */ ? errorNode.d.leftExpr : undefined;
|
|
32
|
+
let rightExpression = errorNode.nodeType === 7 /* ParseNodeType.BinaryOperation */ ? errorNode.d.rightExpr : undefined;
|
|
33
|
+
if (rightExpression?.nodeType === 7 /* ParseNodeType.BinaryOperation */ &&
|
|
34
|
+
!rightExpression.d.hasParens &&
|
|
35
|
+
(0, parseTreeUtils_1.operatorSupportsChaining)(rightExpression.d.operator)) {
|
|
36
|
+
rightExpression = rightExpression.d.leftExpr;
|
|
37
|
+
}
|
|
38
|
+
const runtimeClass = (type) => {
|
|
39
|
+
if (!(0, types_1.isClass)(type))
|
|
40
|
+
return undefined;
|
|
41
|
+
const cls = types_1.TypeBase.isInstance(type) ? types_1.ClassType.cloneAsInstantiable(type) : type.shared.effectiveMetaclass;
|
|
42
|
+
return cls && (0, types_1.isInstantiableClass)(cls) ? cls : undefined;
|
|
43
|
+
};
|
|
44
|
+
const lookupMethod = (type, name, flags) => {
|
|
45
|
+
const cls = runtimeClass(type);
|
|
46
|
+
return cls ? (0, typeUtils_1.lookUpClassMember)(cls, name, flags) : undefined;
|
|
47
|
+
};
|
|
48
|
+
const isBuiltinOrderingMethod = (type, name) => {
|
|
49
|
+
const member = lookupMethod(type, name);
|
|
50
|
+
return (!!member &&
|
|
51
|
+
(0, types_1.isClass)(member.classType) &&
|
|
52
|
+
types_1.ClassType.isBuiltIn(member.classType, ['int', 'float', 'str', 'bytes', 'bytearray', 'tuple', 'list']));
|
|
53
|
+
};
|
|
54
|
+
// Presence and successful binding are separate facts. A failed call to a
|
|
55
|
+
// present user method does not mean Python will try the reflected method.
|
|
56
|
+
const callMethod = (receiver, name, argument, receiverUnexpanded = receiver, argumentUnexpanded = argument) => {
|
|
57
|
+
let result = evaluator.getTypeOfMagicMethodCall(receiverUnexpanded, name, [{ type: argumentUnexpanded }], errorNode, undefined);
|
|
58
|
+
if (!result && (0, types_1.isTypeVar)(receiverUnexpanded) && (0, types_1.isClass)(receiver)) {
|
|
59
|
+
// A union bound has no single lookup class. Bind the selected class
|
|
60
|
+
// method to the original variable rather than replacing Self with a bound.
|
|
61
|
+
result = evaluator.useSpeculativeMode(errorNode, () => {
|
|
62
|
+
const method = evaluator.getBoundMagicMethod(receiver, name, receiverUnexpanded, errorNode);
|
|
63
|
+
if (!method)
|
|
64
|
+
return undefined;
|
|
65
|
+
const call = evaluator.validateCallArgs(errorNode, [{ argCategory: 0 /* ArgCategory.Simple */, typeResult: { type: argumentUnexpanded } }], { type: method }, undefined, true, undefined);
|
|
66
|
+
return call.argumentErrors || !call.returnType
|
|
67
|
+
? undefined
|
|
68
|
+
: { type: call.returnType, isIncomplete: call.isTypeIncomplete };
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (!result && receiverUnexpanded !== receiver) {
|
|
72
|
+
result = evaluator.getTypeOfMagicMethodCall(receiver, name, [{ type: argumentUnexpanded }], errorNode, undefined);
|
|
73
|
+
}
|
|
74
|
+
if (!result && argumentUnexpanded !== argument) {
|
|
75
|
+
result = evaluator.getTypeOfMagicMethodCall(receiver, name, [{ type: argument }], errorNode, undefined);
|
|
76
|
+
}
|
|
77
|
+
if (result)
|
|
78
|
+
return { kind: 'success', result };
|
|
79
|
+
return { kind: lookupMethod(receiver, name, 16 /* MemberAccessFlags.SkipInstanceMembers */) ? 'invalid' : 'missing' };
|
|
80
|
+
};
|
|
81
|
+
const resultTypes = [];
|
|
82
|
+
const reflectionOrder = new Map();
|
|
83
|
+
const boolType = evaluator.getBuiltInObject(errorNode, 'bool');
|
|
84
|
+
const comparedPairs = new Map();
|
|
85
|
+
const pendingPairs = [];
|
|
86
|
+
let hasRecursiveAlias = false;
|
|
87
|
+
let recursiveBudgetExceeded = false;
|
|
88
|
+
const hasUnknownShape = [leftType, rightType].some((type) => type.priv.tupleTypeArgs?.some((arg) => arg.isUnbounded && (0, types_1.isAnyOrUnknown)(arg.type)));
|
|
89
|
+
let requiresDeclaredContract = hasUnknownShape;
|
|
90
|
+
// NotImplemented is a dispatch signal; all other return types are values
|
|
91
|
+
// of the comparison expression, including non-boolean values.
|
|
92
|
+
const classifyResult = (type, left, right) => {
|
|
93
|
+
const values = [];
|
|
94
|
+
let declines = false;
|
|
95
|
+
let preservedTypeVars;
|
|
96
|
+
let declinedTypeVars;
|
|
97
|
+
evaluator.mapSubtypesExpandTypeVars(type, { conditionFilter: [...((0, typeUtils_1.getTypeCondition)(left) ?? []), ...((0, typeUtils_1.getTypeCondition)(right) ?? [])] }, (subtype, unexpandedSubtype) => {
|
|
98
|
+
const typeVar = (0, types_1.isTypeVar)(unexpandedSubtype) &&
|
|
99
|
+
!types_1.TypeVarType.hasConstraints(unexpandedSubtype) &&
|
|
100
|
+
!unexpandedSubtype.shared.recursiveAlias
|
|
101
|
+
? unexpandedSubtype
|
|
102
|
+
: undefined;
|
|
103
|
+
if ((0, types_1.isClassInstance)(subtype) && subtype.shared.fullName === 'types.NotImplementedType') {
|
|
104
|
+
declines = true;
|
|
105
|
+
if (typeVar) {
|
|
106
|
+
(declinedTypeVars ?? (declinedTypeVars = new Set())).add(typeVar);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
if (typeVar) {
|
|
111
|
+
(preservedTypeVars ?? (preservedTypeVars = new Map())).set(values.length, typeVar);
|
|
112
|
+
}
|
|
113
|
+
values.push(subtype);
|
|
114
|
+
}
|
|
115
|
+
return subtype;
|
|
116
|
+
});
|
|
117
|
+
preservedTypeVars?.forEach((typeVar, index) => {
|
|
118
|
+
// A bound is a classification view, not the successful return value.
|
|
119
|
+
// If the bound itself includes NotImplemented, retain only its values.
|
|
120
|
+
if (!declinedTypeVars?.has(typeVar)) {
|
|
121
|
+
values[index] = typeVar;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
return { values, declines };
|
|
125
|
+
};
|
|
126
|
+
const getOrderingResult = (left, right, leftUnexpanded = left, rightUnexpanded = right) => {
|
|
127
|
+
const leftClass = runtimeClass(left);
|
|
128
|
+
const rightClass = runtimeClass(right);
|
|
129
|
+
let reflectedFirst = false;
|
|
130
|
+
if (leftClass && rightClass && !types_1.ClassType.isSameGenericClass(leftClass, rightClass)) {
|
|
131
|
+
let byRight = reflectionOrder.get(leftClass.shared);
|
|
132
|
+
if (!byRight) {
|
|
133
|
+
byRight = new Map();
|
|
134
|
+
reflectionOrder.set(leftClass.shared, byRight);
|
|
135
|
+
}
|
|
136
|
+
const cached = byRight.get(rightClass.shared);
|
|
137
|
+
if (cached !== undefined) {
|
|
138
|
+
reflectedFirst = cached;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
// MROs are already finite and shared across specializations.
|
|
142
|
+
// Reuse the same inheritance lookup across tuple positions.
|
|
143
|
+
reflectedFirst = rightClass.shared.mro.some((base) => {
|
|
144
|
+
evaluator.checkForCancellation();
|
|
145
|
+
return (0, types_1.isClass)(base) && types_1.ClassType.isSameGenericClass(base, leftClass);
|
|
146
|
+
});
|
|
147
|
+
byRight.set(rightClass.shared, reflectedFirst);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const operands = [left, right];
|
|
151
|
+
const unexpandedOperands = [leftUnexpanded, rightUnexpanded];
|
|
152
|
+
const methods = comparisonMethods[operator];
|
|
153
|
+
const values = [];
|
|
154
|
+
for (const index of reflectedFirst ? [1, 0] : [0, 1]) {
|
|
155
|
+
const receiver = operands[index];
|
|
156
|
+
const method = methods[index];
|
|
157
|
+
const call = callMethod(receiver, method, operands[1 - index], unexpandedOperands[index], unexpandedOperands[1 - index]);
|
|
158
|
+
if (call.kind !== 'success') {
|
|
159
|
+
// Invalid user arguments are errors; built-in slots can refuse.
|
|
160
|
+
if (call.kind === 'invalid' && !isBuiltinOrderingMethod(receiver, method)) {
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const result = classifyResult(call.result.type, left, right);
|
|
166
|
+
values.push(...result.values);
|
|
167
|
+
if (!result.declines)
|
|
168
|
+
return values;
|
|
169
|
+
}
|
|
170
|
+
// A refusing or missing fallback does not erase successful values.
|
|
171
|
+
return values.length ? values : undefined;
|
|
172
|
+
};
|
|
173
|
+
const getDeclaredContractResult = () => {
|
|
174
|
+
const contract = (type) => {
|
|
175
|
+
const elementType = evaluator.stripLiteralValue((0, types_1.getInferredTupleLiteralBase)(type.priv.typeArgs?.[0] ?? types_1.UnknownType.create()));
|
|
176
|
+
return types_1.ClassType.specialize(type, [elementType], true, undefined, [
|
|
177
|
+
{ type: elementType, isUnbounded: true },
|
|
178
|
+
]);
|
|
179
|
+
};
|
|
180
|
+
const values = getOrderingResult(contract(leftType), contract(rightType));
|
|
181
|
+
return values ? (0, types_1.combineTypes)(values) : undefined;
|
|
182
|
+
};
|
|
183
|
+
const getRecursiveBudgetFallback = () => {
|
|
184
|
+
const declared = getDeclaredContractResult();
|
|
185
|
+
if (!declared)
|
|
186
|
+
return undefined;
|
|
187
|
+
const isClosedResult = (type) => {
|
|
188
|
+
let size = 0;
|
|
189
|
+
const visit = (type, depth) => {
|
|
190
|
+
if (++size > types_1.maxSubtypesForInferredType ||
|
|
191
|
+
depth > types_1.maxTypeRecursionCount ||
|
|
192
|
+
type.props?.inferredTupleLiteral ||
|
|
193
|
+
type.props?.typeForm ||
|
|
194
|
+
(0, typeUtils_1.getTypeCondition)(type)?.length)
|
|
195
|
+
return false;
|
|
196
|
+
if ((0, types_1.isAnyOrUnknown)(type) || (0, types_1.isNever)(type))
|
|
197
|
+
return true;
|
|
198
|
+
if ((0, types_1.isUnion)(type))
|
|
199
|
+
return type.priv.subtypes.every((subtype) => visit(subtype, depth + 1));
|
|
200
|
+
if (!(0, types_1.isClass)(type) || type.priv.typedDictNarrowedEntries)
|
|
201
|
+
return false;
|
|
202
|
+
const argsAreClosed = type.priv.tupleTypeArgs
|
|
203
|
+
? type.priv.tupleTypeArgs.every((arg) => visit(arg.type, depth + 1))
|
|
204
|
+
: type.priv.typeArgs?.every((arg) => visit(arg, depth + 1)) ?? true;
|
|
205
|
+
return (argsAreClosed && ((0, types_1.getTypeAliasInfo)(type)?.typeArgs?.every((arg) => visit(arg, depth + 1)) ?? true));
|
|
206
|
+
};
|
|
207
|
+
return visit(type, 0);
|
|
208
|
+
};
|
|
209
|
+
// Keep cheap results already reached, but never combine growing generic graphs.
|
|
210
|
+
return (0, types_1.combineTypes)([
|
|
211
|
+
...resultTypes.filter((type) => (0, types_1.isAnyOrUnknown)(type) ||
|
|
212
|
+
((0, types_1.isClassInstance)(type) &&
|
|
213
|
+
!types_1.ClassType.isBuiltIn(type, 'bool') &&
|
|
214
|
+
((!type.priv.typeArgs?.length && !type.priv.tupleTypeArgs?.length) || isClosedResult(type)))),
|
|
215
|
+
declared,
|
|
216
|
+
]);
|
|
217
|
+
};
|
|
218
|
+
// Earlier comparisons can mutate objects or rebind names after a middle operand is captured.
|
|
219
|
+
const isChainedMiddleOperand = errorNode.nodeType === 7 /* ParseNodeType.BinaryOperation */ &&
|
|
220
|
+
!errorNode.d.hasParens &&
|
|
221
|
+
errorNode.parent?.nodeType === 7 /* ParseNodeType.BinaryOperation */ &&
|
|
222
|
+
errorNode.parent.d.rightExpr === errorNode &&
|
|
223
|
+
(0, parseTreeUtils_1.operatorSupportsChaining)(errorNode.parent.d.operator);
|
|
224
|
+
const sameName = (left, right) => {
|
|
225
|
+
if (isChainedMiddleOperand ||
|
|
226
|
+
left?.nodeType !== 38 /* ParseNodeType.Name */ ||
|
|
227
|
+
right?.nodeType !== 38 /* ParseNodeType.Name */ ||
|
|
228
|
+
left.d.value !== right.d.value) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
const first = evaluator.lookUpSymbolRecursive(left, left.d.value, false);
|
|
232
|
+
const second = evaluator.lookUpSymbolRecursive(right, right.d.value, false);
|
|
233
|
+
return (!!first &&
|
|
234
|
+
!!second &&
|
|
235
|
+
first.scope.type !== 3 /* ScopeType.Class */ &&
|
|
236
|
+
second.scope.type !== 3 /* ScopeType.Class */ &&
|
|
237
|
+
first.symbol === second.symbol);
|
|
238
|
+
};
|
|
239
|
+
if (sameName(leftExpression, rightExpression)) {
|
|
240
|
+
return boolType;
|
|
241
|
+
}
|
|
242
|
+
let pureOperands;
|
|
243
|
+
let identityBudgetExceeded = false;
|
|
244
|
+
const sameReferenceAt = (leftIndex, rightIndex, depth) => {
|
|
245
|
+
if (depth !== 0 ||
|
|
246
|
+
leftExpression?.nodeType !== 52 /* ParseNodeType.Tuple */ ||
|
|
247
|
+
rightExpression?.nodeType !== 52 /* ParseNodeType.Tuple */ ||
|
|
248
|
+
!sameName(leftExpression.d.items[leftIndex], rightExpression.d.items[rightIndex])) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
if (pureOperands === undefined) {
|
|
252
|
+
const pending = [leftExpression, rightExpression];
|
|
253
|
+
let remaining = types_1.maxSubtypesForInferredType;
|
|
254
|
+
pureOperands = true;
|
|
255
|
+
while (pending.length) {
|
|
256
|
+
if (--remaining < 0) {
|
|
257
|
+
identityBudgetExceeded = true;
|
|
258
|
+
pureOperands = false;
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
const node = pending.pop();
|
|
262
|
+
if (node.nodeType === 38 /* ParseNodeType.Name */ ||
|
|
263
|
+
node.nodeType === 40 /* ParseNodeType.Number */ ||
|
|
264
|
+
node.nodeType === 14 /* ParseNodeType.Constant */) {
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (node.nodeType === 48 /* ParseNodeType.StringList */) {
|
|
268
|
+
if (node.d.strings.every((item) => item.nodeType === 49 /* ParseNodeType.String */)) {
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
else if (node.nodeType === 52 /* ParseNodeType.Tuple */ || node.nodeType === 34 /* ParseNodeType.List */) {
|
|
273
|
+
if (node.d.items.length > remaining) {
|
|
274
|
+
identityBudgetExceeded = true;
|
|
275
|
+
pureOperands = false;
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
pending.push(...node.d.items);
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
pureOperands = false;
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return pureOperands;
|
|
286
|
+
};
|
|
287
|
+
// Built-in containers use their declared sequence semantics; explicit
|
|
288
|
+
// subclass types use their declared methods without callee-body analysis.
|
|
289
|
+
const canOrderResolvedPair = (left, right, recursionCount, isConditional, leftUnexpanded, rightUnexpanded) => {
|
|
290
|
+
if ((0, types_1.isAnyOrUnknown)(left) || (0, types_1.isAnyOrUnknown)(right)) {
|
|
291
|
+
// Opaque shape facts use the old contract, not an additional Unknown result.
|
|
292
|
+
if (!hasUnknownShape) {
|
|
293
|
+
resultTypes.push((0, types_1.isAnyOrUnknown)(left) ? left : right);
|
|
294
|
+
}
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
if ((0, types_1.isClassInstance)(left) && (0, types_1.isClassInstance)(right)) {
|
|
298
|
+
if ((0, typeUtils_1.isTupleClass)(left) && (0, typeUtils_1.isTupleClass)(right) && left.priv.tupleTypeArgs && right.priv.tupleTypeArgs) {
|
|
299
|
+
return canOrderArgs(left.priv.tupleTypeArgs, right.priv.tupleTypeArgs, recursionCount, isConditional);
|
|
300
|
+
}
|
|
301
|
+
if (types_1.ClassType.isBuiltIn(left, 'list') && types_1.ClassType.isBuiltIn(right, 'list')) {
|
|
302
|
+
resultTypes.push(boolType);
|
|
303
|
+
const leftElement = left.priv.typeArgs?.[0] ?? types_1.UnknownType.create();
|
|
304
|
+
const rightElement = right.priv.typeArgs?.[0] ?? types_1.UnknownType.create();
|
|
305
|
+
return canOrderElements(leftElement, rightElement, recursionCount + 1, isConditional);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (hasRecursiveAlias) {
|
|
309
|
+
const args = [left, right].flatMap((type) => ((0, types_1.isClassInstance)(type) ? type.priv.typeArgs ?? [] : []));
|
|
310
|
+
if (!(0, types_1.getTupleLiteralTypeComplexity)(args)) {
|
|
311
|
+
recursiveBudgetExceeded = true;
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
const values = getOrderingResult(left, right, leftUnexpanded, rightUnexpanded);
|
|
316
|
+
if (!values) {
|
|
317
|
+
// Types alone cannot determine whether equal objects skip this call.
|
|
318
|
+
// Discard optional precision instead of recovering source identities.
|
|
319
|
+
if ((0, types_1.isClassInstance)(left) &&
|
|
320
|
+
(0, types_1.isClassInstance)(right) &&
|
|
321
|
+
(types_1.ClassType.isSameGenericClass(left, right) ||
|
|
322
|
+
types_1.ClassType.isBuiltIn(left, 'object') ||
|
|
323
|
+
types_1.ClassType.isBuiltIn(right, 'object'))) {
|
|
324
|
+
requiresDeclaredContract = true;
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
resultTypes.push(...values);
|
|
330
|
+
return true;
|
|
331
|
+
};
|
|
332
|
+
const canOrderElementsUncached = (left, right, recursionCount, isConditional) => {
|
|
333
|
+
if ((0, types_1.exceedsInferredTupleLiteralProduct)(left, right)) {
|
|
334
|
+
left = (0, types_1.getInferredTupleLiteralBase)(left);
|
|
335
|
+
right = (0, types_1.getInferredTupleLiteralBase)(right);
|
|
336
|
+
}
|
|
337
|
+
// Primitive literals affect equality and custom overload selection,
|
|
338
|
+
// but not ordering between built-in scalar families. Collapse these
|
|
339
|
+
// operation-local views before expanding a large literal union.
|
|
340
|
+
const subtypes = (type) => ((0, types_1.isUnion)(type) ? type.priv.subtypes : [type]);
|
|
341
|
+
const primitivesOnly = (type) => subtypes(type).every((subtype) => (0, types_1.isClassInstance)(subtype) &&
|
|
342
|
+
types_1.ClassType.isBuiltIn(subtype, ['int', 'bool', 'float', 'complex', 'str', 'bytes']));
|
|
343
|
+
if (primitivesOnly(left) && primitivesOnly(right)) {
|
|
344
|
+
left = evaluator.stripLiteralValue(left);
|
|
345
|
+
right = evaluator.stripLiteralValue(right);
|
|
346
|
+
}
|
|
347
|
+
// A common bool contract proves an entire union without a Cartesian
|
|
348
|
+
// product. Require valid calls for the whole opposing union, inspect
|
|
349
|
+
// both declared dispatch directions, and retain NotImplemented fallback.
|
|
350
|
+
if ((0, types_1.isUnion)(left) || (0, types_1.isUnion)(right)) {
|
|
351
|
+
const summarize = (receiver, argument, method) => {
|
|
352
|
+
let completes = true;
|
|
353
|
+
for (const subtype of subtypes(receiver)) {
|
|
354
|
+
evaluator.checkForCancellation();
|
|
355
|
+
if (!runtimeClass(subtype))
|
|
356
|
+
return undefined;
|
|
357
|
+
const member = lookupMethod(subtype, method, 16 /* MemberAccessFlags.SkipInstanceMembers */);
|
|
358
|
+
// Built-in container annotations do not describe the
|
|
359
|
+
// element comparison's actual return type. Recurse below.
|
|
360
|
+
if (member && (0, types_1.isClass)(member.classType) && types_1.ClassType.isBuiltIn(member.classType, ['tuple', 'list']))
|
|
361
|
+
return undefined;
|
|
362
|
+
const call = callMethod(subtype, method, argument);
|
|
363
|
+
if (call.kind !== 'success') {
|
|
364
|
+
if (call.kind === 'invalid')
|
|
365
|
+
return undefined;
|
|
366
|
+
completes = false;
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
const result = classifyResult(call.result.type, subtype, argument);
|
|
370
|
+
if (!result.values.every((type) => (0, types_1.isClassInstance)(type) && types_1.ClassType.isBuiltIn(type, 'bool')))
|
|
371
|
+
return undefined;
|
|
372
|
+
completes && (completes = !result.declines);
|
|
373
|
+
}
|
|
374
|
+
return { completes };
|
|
375
|
+
};
|
|
376
|
+
const methods = comparisonMethods[operator];
|
|
377
|
+
const forward = summarize(left, right, methods[0]);
|
|
378
|
+
const reflected = forward ? summarize(right, left, methods[1]) : undefined;
|
|
379
|
+
if (forward && reflected && (forward.completes || reflected.completes)) {
|
|
380
|
+
resultTypes.push(boolType);
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
// Use expanded views for dispatch and original operands for method binding.
|
|
385
|
+
// Keep the evaluator's conditions so correlated constraints are not crossed.
|
|
386
|
+
let valid = true;
|
|
387
|
+
evaluator.mapSubtypesExpandTypeVars(left, undefined, (leftSubtype, leftUnexpanded) => {
|
|
388
|
+
evaluator.mapSubtypesExpandTypeVars(right, { conditionFilter: (0, typeUtils_1.getTypeCondition)(leftSubtype) }, (rightSubtype, rightUnexpanded) => {
|
|
389
|
+
if (!valid && !isConditional) {
|
|
390
|
+
return rightSubtype;
|
|
391
|
+
}
|
|
392
|
+
hasRecursiveAlias || (hasRecursiveAlias = ((0, types_1.isTypeVar)(leftUnexpanded) && !!leftUnexpanded.shared.recursiveAlias) ||
|
|
393
|
+
((0, types_1.isTypeVar)(rightUnexpanded) && !!rightUnexpanded.shared.recursiveAlias));
|
|
394
|
+
valid =
|
|
395
|
+
canOrderResolvedPair(leftSubtype, rightSubtype, recursionCount, isConditional, leftUnexpanded, rightUnexpanded) && valid;
|
|
396
|
+
return rightSubtype;
|
|
397
|
+
});
|
|
398
|
+
return leftSubtype;
|
|
399
|
+
});
|
|
400
|
+
return valid;
|
|
401
|
+
};
|
|
402
|
+
// Recursive specialization can clone placeholders and expanded classes.
|
|
403
|
+
// Limit new obligations instead of equating different alias arguments.
|
|
404
|
+
const aliasSpecializations = new Map();
|
|
405
|
+
const canOrderElements = (left, right, depth, isConditional) => {
|
|
406
|
+
let rights = comparedPairs.get(left);
|
|
407
|
+
if (!rights) {
|
|
408
|
+
rights = new Map();
|
|
409
|
+
comparedPairs.set(left, rights);
|
|
410
|
+
}
|
|
411
|
+
const previous = rights.get(right);
|
|
412
|
+
if (previous === false || (previous === true && isConditional))
|
|
413
|
+
return true;
|
|
414
|
+
rights.set(right, isConditional);
|
|
415
|
+
const leftAlias = (0, types_1.getTypeAliasInfo)(left);
|
|
416
|
+
const rightAlias = (0, types_1.getTypeAliasInfo)(right);
|
|
417
|
+
hasRecursiveAlias || (hasRecursiveAlias = ((0, types_1.isTypeVar)(left) && !!left.shared.recursiveAlias) || ((0, types_1.isTypeVar)(right) && !!right.shared.recursiveAlias));
|
|
418
|
+
const aliases = leftAlias?.shared === rightAlias?.shared ? [leftAlias?.shared] : [leftAlias?.shared, rightAlias?.shared];
|
|
419
|
+
for (const alias of aliases) {
|
|
420
|
+
if (!alias)
|
|
421
|
+
continue;
|
|
422
|
+
const count = aliasSpecializations.get(alias) ?? 0;
|
|
423
|
+
if (count >= types_1.maxSubtypesForInferredType) {
|
|
424
|
+
recursiveBudgetExceeded = true;
|
|
425
|
+
return false;
|
|
426
|
+
}
|
|
427
|
+
aliasSpecializations.set(alias, count + 1);
|
|
428
|
+
}
|
|
429
|
+
pendingPairs.push({ left, right, depth, isConditional });
|
|
430
|
+
return true;
|
|
431
|
+
};
|
|
432
|
+
// Literal type identity differs from Python value equality: True and 1
|
|
433
|
+
// have distinct literal types, but compare equal inside a tuple.
|
|
434
|
+
const literalEquality = (left, right) => {
|
|
435
|
+
if (!(0, types_1.isClassInstance)(left) || !(0, types_1.isClassInstance)(right) || !(0, typeUtils_1.isLiteralType)(left) || !(0, typeUtils_1.isLiteralType)(right)) {
|
|
436
|
+
return undefined;
|
|
437
|
+
}
|
|
438
|
+
if (types_1.ClassType.isBuiltIn(left, ['int', 'bool']) && types_1.ClassType.isBuiltIn(right, ['int', 'bool'])) {
|
|
439
|
+
const a = left.priv.literalValue;
|
|
440
|
+
const b = right.priv.literalValue;
|
|
441
|
+
if ((typeof a === 'number' || typeof a === 'bigint' || typeof a === 'boolean') &&
|
|
442
|
+
(typeof b === 'number' || typeof b === 'bigint' || typeof b === 'boolean')) {
|
|
443
|
+
return BigInt(a) === BigInt(b);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
if (!types_1.ClassType.isSameGenericClass(left, right) &&
|
|
447
|
+
types_1.ClassType.isBuiltIn(left, ['int', 'bool', 'str', 'bytes']) &&
|
|
448
|
+
types_1.ClassType.isBuiltIn(right, ['int', 'bool', 'str', 'bytes'])) {
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
return undefined;
|
|
452
|
+
};
|
|
453
|
+
const getNumericRepresentation = (type) => {
|
|
454
|
+
if ((0, types_1.isTypeVar)(type) && type.shared.recursiveAlias)
|
|
455
|
+
return undefined;
|
|
456
|
+
const concrete = (0, types_1.isTypeVar)(type) ? evaluator.makeTopLevelTypeVarsConcrete(type) : type;
|
|
457
|
+
const subtypes = (0, types_1.isUnion)(concrete) ? concrete.priv.subtypes : [concrete];
|
|
458
|
+
if (subtypes.length > types_1.maxSubtypesForInferredType)
|
|
459
|
+
return undefined;
|
|
460
|
+
let representation = 'literal';
|
|
461
|
+
for (const subtype of subtypes) {
|
|
462
|
+
if (!(0, types_1.isClassInstance)(subtype) || !types_1.ClassType.isBuiltIn(subtype, ['int', 'bool', 'float', 'complex'])) {
|
|
463
|
+
return undefined;
|
|
464
|
+
}
|
|
465
|
+
if (types_1.ClassType.isBuiltIn(subtype, ['float', 'complex']))
|
|
466
|
+
representation = 'unrepresented';
|
|
467
|
+
}
|
|
468
|
+
return representation;
|
|
469
|
+
};
|
|
470
|
+
const equalityResults = new Map();
|
|
471
|
+
const getEquality = (left, right, depth) => {
|
|
472
|
+
if (depth > types_1.maxTypeRecursionCount)
|
|
473
|
+
return undefined;
|
|
474
|
+
let rights = equalityResults.get(left);
|
|
475
|
+
if (!rights) {
|
|
476
|
+
rights = new Map();
|
|
477
|
+
equalityResults.set(left, rights);
|
|
478
|
+
}
|
|
479
|
+
const cached = rights.get(right);
|
|
480
|
+
if (cached && cached.depth <= depth)
|
|
481
|
+
return cached.value;
|
|
482
|
+
// An active cycle is unknown; a depth-limited result must not replace
|
|
483
|
+
// the more complete result of a shallower visit.
|
|
484
|
+
const entry = { depth, value: undefined };
|
|
485
|
+
rights.set(right, entry);
|
|
486
|
+
entry.value = getEqualityUncached(left, right, depth);
|
|
487
|
+
return entry.value;
|
|
488
|
+
};
|
|
489
|
+
const getEqualityUncached = (left, right, depth) => {
|
|
490
|
+
const equal = literalEquality(left, right);
|
|
491
|
+
if (equal !== undefined)
|
|
492
|
+
return equal;
|
|
493
|
+
// Compare singleton types directly, but keep tuple graphs on the
|
|
494
|
+
// memoized element path rather than unfolding them in isTypeSame.
|
|
495
|
+
if (((0, typeUtils_1.isNoneInstance)(left) ||
|
|
496
|
+
((0, types_1.isClassInstance)(left) &&
|
|
497
|
+
((0, typeUtils_1.isLiteralType)(left) ||
|
|
498
|
+
['types.EllipsisType', 'types.NotImplementedType'].includes(left.shared.fullName)))) &&
|
|
499
|
+
(0, types_1.isTypeSame)(left, right))
|
|
500
|
+
return true;
|
|
501
|
+
const leftNumeric = getNumericRepresentation(left);
|
|
502
|
+
const rightNumeric = leftNumeric ? getNumericRepresentation(right) : undefined;
|
|
503
|
+
if (leftNumeric && rightNumeric && (leftNumeric === 'unrepresented' || rightNumeric === 'unrepresented')) {
|
|
504
|
+
return 'unrepresented';
|
|
505
|
+
}
|
|
506
|
+
if (!(0, types_1.isClassInstance)(left) || !(0, types_1.isClassInstance)(right))
|
|
507
|
+
return undefined;
|
|
508
|
+
if ((0, typeUtils_1.isTupleClass)(left) && (0, typeUtils_1.isTupleClass)(right)) {
|
|
509
|
+
const leftArgs = left.priv.tupleTypeArgs;
|
|
510
|
+
const rightArgs = right.priv.tupleTypeArgs;
|
|
511
|
+
if (!leftArgs ||
|
|
512
|
+
!rightArgs ||
|
|
513
|
+
leftArgs.some((arg) => arg.isUnbounded || arg.isOptional) ||
|
|
514
|
+
rightArgs.some((arg) => arg.isUnbounded || arg.isOptional)) {
|
|
515
|
+
return undefined;
|
|
516
|
+
}
|
|
517
|
+
if (leftArgs.length !== rightArgs.length)
|
|
518
|
+
return false;
|
|
519
|
+
let allEqual = true;
|
|
520
|
+
let unrepresentedEquality = false;
|
|
521
|
+
for (let index = 0; index < leftArgs.length; index++) {
|
|
522
|
+
const equality = getEquality(leftArgs[index].type, rightArgs[index].type, depth + 1);
|
|
523
|
+
if (equality === false)
|
|
524
|
+
return false;
|
|
525
|
+
allEqual && (allEqual = equality === true);
|
|
526
|
+
unrepresentedEquality || (unrepresentedEquality = equality === 'unrepresented');
|
|
527
|
+
}
|
|
528
|
+
return allEqual ? true : unrepresentedEquality ? 'unrepresented' : undefined;
|
|
529
|
+
}
|
|
530
|
+
if ((0, typeUtils_1.isLiteralType)(left) &&
|
|
531
|
+
(0, typeUtils_1.isLiteralType)(right) &&
|
|
532
|
+
types_1.ClassType.isSameGenericClass(left, right) &&
|
|
533
|
+
(typeof left.priv.literalValue === 'string' ||
|
|
534
|
+
typeof left.priv.literalValue === 'number' ||
|
|
535
|
+
typeof left.priv.literalValue === 'bigint' ||
|
|
536
|
+
typeof left.priv.literalValue === 'boolean') &&
|
|
537
|
+
left.priv.literalValue !== right.priv.literalValue)
|
|
538
|
+
return false;
|
|
539
|
+
return undefined;
|
|
540
|
+
};
|
|
541
|
+
const getTupleLiteralItems = (expression, args) => {
|
|
542
|
+
if (expression?.nodeType !== 52 /* ParseNodeType.Tuple */ ||
|
|
543
|
+
args.length > types_1.maxSubtypesForInferredType ||
|
|
544
|
+
expression.d.items.length !== args.length ||
|
|
545
|
+
isChainedMiddleOperand ||
|
|
546
|
+
expression.d.items.some((item, index) => item.nodeType === 56 /* ParseNodeType.Unpack */ || args[index].isUnbounded || args[index].isOptional)) {
|
|
547
|
+
return undefined;
|
|
548
|
+
}
|
|
549
|
+
return expression.d.items;
|
|
550
|
+
};
|
|
551
|
+
const canOrderArgs = (leftArgs, rightArgs, recursionCount, isConditional) => {
|
|
552
|
+
// When both tuples begin with an arbitrary run of the same literal,
|
|
553
|
+
// a fixed run of that literal immediately afterward only changes the
|
|
554
|
+
// minimum lengths. Both relative run lengths are still unbounded, so
|
|
555
|
+
// the set of reachable suffix alignments is unchanged. This does not
|
|
556
|
+
// apply when only one operand has an unbounded prefix.
|
|
557
|
+
if (leftArgs[0]?.isUnbounded &&
|
|
558
|
+
rightArgs[0]?.isUnbounded &&
|
|
559
|
+
getEquality(leftArgs[0].type, rightArgs[0].type, 0) === true) {
|
|
560
|
+
const collapse = (args) => {
|
|
561
|
+
let index = 1;
|
|
562
|
+
while (index < args.length &&
|
|
563
|
+
!args[index].isUnbounded &&
|
|
564
|
+
!args[index].isOptional &&
|
|
565
|
+
getEquality(args[0].type, args[index].type, 0) === true)
|
|
566
|
+
index++;
|
|
567
|
+
return index > 1 ? [args[0], ...args.slice(index)] : args;
|
|
568
|
+
};
|
|
569
|
+
leftArgs = collapse(leftArgs);
|
|
570
|
+
rightArgs = collapse(rightArgs);
|
|
571
|
+
}
|
|
572
|
+
// If every possible element pair has a bool contract, alignment cannot
|
|
573
|
+
// change validity or the result. Prove this before expanding a large
|
|
574
|
+
// variadic suffix into a quadratic number of positions. Only flat
|
|
575
|
+
// declared classes enter this proof, so it cannot queue nested work.
|
|
576
|
+
const flat = (type) => (0, types_1.isUnion)(type)
|
|
577
|
+
? type.priv.subtypes.every(flat)
|
|
578
|
+
: (0, types_1.isClassInstance)(type) && !(0, typeUtils_1.isTupleClass)(type) && !types_1.ClassType.isBuiltIn(type, 'list');
|
|
579
|
+
if (leftArgs.length &&
|
|
580
|
+
rightArgs.length &&
|
|
581
|
+
leftArgs.every((arg) => flat(arg.type)) &&
|
|
582
|
+
rightArgs.every((arg) => flat(arg.type))) {
|
|
583
|
+
const start = resultTypes.length;
|
|
584
|
+
const valid = canOrderElementsUncached((0, types_1.combineTypes)(leftArgs.map((arg) => arg.type)), (0, types_1.combineTypes)(rightArgs.map((arg) => arg.type)), recursionCount + 1, isConditional);
|
|
585
|
+
if (valid && resultTypes.length > start) {
|
|
586
|
+
if (resultTypes.slice(start).every((type) => (0, types_1.isClassInstance)(type) && types_1.ClassType.isBuiltIn(type, 'bool'))) {
|
|
587
|
+
resultTypes.length = start;
|
|
588
|
+
resultTypes.push(boolType);
|
|
589
|
+
return true;
|
|
590
|
+
}
|
|
591
|
+
const homogeneous = (args) => args.every((arg) => (0, types_1.isClassInstance)(arg.type) &&
|
|
592
|
+
!arg.type.shared.typeParams.length &&
|
|
593
|
+
!arg.type.priv.typeArgs?.length &&
|
|
594
|
+
!arg.type.priv.tupleTypeArgs &&
|
|
595
|
+
arg.type.priv.literalValue === undefined &&
|
|
596
|
+
!types_1.ClassType.isTypedDictClass(arg.type) &&
|
|
597
|
+
!(0, types_1.getTypeAliasInfo)(arg.type) &&
|
|
598
|
+
!(0, typeUtils_1.getTypeCondition)(arg.type)?.length &&
|
|
599
|
+
!arg.type.props?.inferredTupleLiteral &&
|
|
600
|
+
(0, types_1.isTypeSame)(args[0].type, arg.type, { honorCallBehavior: true }));
|
|
601
|
+
if (leftArgs[0].isUnbounded &&
|
|
602
|
+
rightArgs[0].isUnbounded &&
|
|
603
|
+
homogeneous(leftArgs) &&
|
|
604
|
+
homogeneous(rightArgs) &&
|
|
605
|
+
getEquality(leftArgs[0].type, rightArgs[0].type, recursionCount + 1) === undefined) {
|
|
606
|
+
// Every reachable pair has this same closed contract. The
|
|
607
|
+
// unbounded prefixes can also be equal or differ in length.
|
|
608
|
+
resultTypes.push(boolType);
|
|
609
|
+
return true;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
resultTypes.length = start;
|
|
613
|
+
}
|
|
614
|
+
// An unbounded argument can consume zero or more positions.
|
|
615
|
+
// Check every reachable alignment before accepting tuple ordering.
|
|
616
|
+
const leftItems = recursionCount === 0 ? getTupleLiteralItems(leftExpression, leftArgs) : undefined;
|
|
617
|
+
const rightItems = recursionCount === 0 ? getTupleLiteralItems(rightExpression, rightArgs) : undefined;
|
|
618
|
+
const pending = [[0, 0, isConditional]];
|
|
619
|
+
const visited = new Set();
|
|
620
|
+
while (pending.length > 0) {
|
|
621
|
+
evaluator.checkForCancellation();
|
|
622
|
+
const [leftIndex, rightIndex, conditional] = pending.pop();
|
|
623
|
+
const position = `${leftIndex},${rightIndex},${conditional}`;
|
|
624
|
+
if (visited.has(position)) {
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
visited.add(position);
|
|
628
|
+
if (leftIndex === leftArgs.length || rightIndex === rightArgs.length) {
|
|
629
|
+
resultTypes.push(boolType);
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
const leftArg = leftArgs[leftIndex];
|
|
633
|
+
const rightArg = rightArgs[rightIndex];
|
|
634
|
+
if (leftArg.isUnbounded || leftArg.isOptional) {
|
|
635
|
+
pending.push([leftIndex + 1, rightIndex, conditional]);
|
|
636
|
+
}
|
|
637
|
+
if (rightArg.isUnbounded || rightArg.isOptional) {
|
|
638
|
+
pending.push([leftIndex, rightIndex + 1, conditional]);
|
|
639
|
+
}
|
|
640
|
+
let equality = getEquality(leftArg.type, rightArg.type, recursionCount + 1);
|
|
641
|
+
const leftItem = equality !== true ? leftItems?.[leftIndex] : undefined;
|
|
642
|
+
const rightItem = equality !== true ? rightItems?.[rightIndex] : undefined;
|
|
643
|
+
const leftList = leftItem?.nodeType === 34 /* ParseNodeType.List */ ? leftItem : undefined;
|
|
644
|
+
const rightList = rightItem?.nodeType === 34 /* ParseNodeType.List */ ? rightItem : undefined;
|
|
645
|
+
const emptyListPair = leftList &&
|
|
646
|
+
rightList &&
|
|
647
|
+
(!leftList.d.items.length || !rightList.d.items.length) &&
|
|
648
|
+
(0, types_1.isClassInstance)(leftArg.type) &&
|
|
649
|
+
(0, types_1.isClassInstance)(rightArg.type) &&
|
|
650
|
+
types_1.ClassType.isBuiltIn(leftArg.type, 'list') &&
|
|
651
|
+
types_1.ClassType.isBuiltIn(rightArg.type, 'list');
|
|
652
|
+
if (emptyListPair) {
|
|
653
|
+
// An unpack or comprehension can still produce an empty list.
|
|
654
|
+
const firstKind = (leftList.d.items[0] ?? rightList.d.items[0])?.nodeType;
|
|
655
|
+
if (firstKind === undefined) {
|
|
656
|
+
equality = true;
|
|
657
|
+
}
|
|
658
|
+
else if (firstKind !== 56 /* ParseNodeType.Unpack */ && firstKind !== 11 /* ParseNodeType.Comprehension */) {
|
|
659
|
+
equality = false;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
if (equality !== true &&
|
|
663
|
+
!leftList &&
|
|
664
|
+
!rightList &&
|
|
665
|
+
!leftArg.isUnbounded &&
|
|
666
|
+
!rightArg.isUnbounded &&
|
|
667
|
+
!leftArg.isOptional &&
|
|
668
|
+
!rightArg.isOptional &&
|
|
669
|
+
sameReferenceAt(leftIndex, rightIndex, recursionCount)) {
|
|
670
|
+
equality = true;
|
|
671
|
+
}
|
|
672
|
+
const unrepresented = equality === 'unrepresented';
|
|
673
|
+
if (equality !== true) {
|
|
674
|
+
if (emptyListPair) {
|
|
675
|
+
// A nominal list can be a subclass whose __eq__ mutates the other operand.
|
|
676
|
+
resultTypes.push(boolType);
|
|
677
|
+
}
|
|
678
|
+
else if (!canOrderElements(leftArg.type, rightArg.type, recursionCount + 1, conditional || (unrepresented && !!getNumericRepresentation(leftArg.type)))) {
|
|
679
|
+
return false;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
if (equality === false)
|
|
683
|
+
continue;
|
|
684
|
+
// Unrepresented numeric equality can still reach a custom suffix.
|
|
685
|
+
// Preserve its results, using the old contract if a conditional call fails.
|
|
686
|
+
const nextConditional = conditional || unrepresented;
|
|
687
|
+
pending.push([leftIndex + 1, rightIndex + 1, nextConditional]);
|
|
688
|
+
if (leftArg.isUnbounded) {
|
|
689
|
+
pending.push([leftIndex, rightIndex + 1, nextConditional]);
|
|
690
|
+
}
|
|
691
|
+
if (rightArg.isUnbounded) {
|
|
692
|
+
pending.push([leftIndex + 1, rightIndex, nextConditional]);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
return true;
|
|
696
|
+
};
|
|
697
|
+
const ordered = canOrderArgs(leftType.priv.tupleTypeArgs, rightType.priv.tupleTypeArgs, 0,
|
|
698
|
+
/* isConditional */ false);
|
|
699
|
+
if (!ordered)
|
|
700
|
+
return recursiveBudgetExceeded ? getRecursiveBudgetFallback() : undefined;
|
|
701
|
+
if (identityBudgetExceeded) {
|
|
702
|
+
return getDeclaredContractResult();
|
|
703
|
+
}
|
|
704
|
+
// Reach seed elements before expanding another recursive tail.
|
|
705
|
+
for (let index = 0; index < pendingPairs.length; index++) {
|
|
706
|
+
evaluator.checkForCancellation();
|
|
707
|
+
const pair = pendingPairs[index];
|
|
708
|
+
const valid = canOrderElementsUncached(pair.left, pair.right, pair.depth, pair.isConditional);
|
|
709
|
+
if (recursiveBudgetExceeded)
|
|
710
|
+
return getRecursiveBudgetFallback();
|
|
711
|
+
if (!valid) {
|
|
712
|
+
if (!pair.isConditional)
|
|
713
|
+
return undefined;
|
|
714
|
+
requiresDeclaredContract = true;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
if (requiresDeclaredContract) {
|
|
718
|
+
const declaredResult = getDeclaredContractResult();
|
|
719
|
+
return declaredResult ? (0, types_1.combineTypes)([...resultTypes, declaredResult]) : undefined;
|
|
720
|
+
}
|
|
721
|
+
// A length comparison contributes an unconditional bool. It also covers
|
|
722
|
+
// conditional bool results from constrained receiver types.
|
|
723
|
+
if (resultTypes.some((type) => (0, types_1.isTypeSame)(type, boolType))) {
|
|
724
|
+
return (0, types_1.combineTypes)([
|
|
725
|
+
...resultTypes.filter((type) => !((0, types_1.isClassInstance)(type) && types_1.ClassType.isBuiltIn(type, 'bool'))),
|
|
726
|
+
boolType,
|
|
727
|
+
]);
|
|
728
|
+
}
|
|
729
|
+
return (0, types_1.combineTypes)(resultTypes);
|
|
730
|
+
}
|
|
731
|
+
//# sourceMappingURL=tupleComparison.js.map
|