@zzzen/pyright-internal 1.2.0-dev.20230430 → 1.2.0-dev.20230514
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/backgroundAnalysisProgram.d.ts +4 -1
- package/dist/analyzer/backgroundAnalysisProgram.js +12 -0
- package/dist/analyzer/backgroundAnalysisProgram.js.map +1 -1
- package/dist/analyzer/checker.d.ts +1 -0
- package/dist/analyzer/checker.js +89 -6
- package/dist/analyzer/checker.js.map +1 -1
- package/dist/analyzer/constraintSolver.js +14 -15
- package/dist/analyzer/constraintSolver.js.map +1 -1
- package/dist/analyzer/constructors.d.ts +6 -0
- package/dist/analyzer/constructors.js +513 -0
- package/dist/analyzer/constructors.js.map +1 -0
- package/dist/analyzer/dataClasses.js +86 -2
- package/dist/analyzer/dataClasses.js.map +1 -1
- package/dist/analyzer/docStringConversion.js +1 -1
- package/dist/analyzer/docStringConversion.js.map +1 -1
- package/dist/analyzer/enums.js +62 -8
- package/dist/analyzer/enums.js.map +1 -1
- package/dist/analyzer/importResolver.js +47 -29
- package/dist/analyzer/importResolver.js.map +1 -1
- package/dist/analyzer/importStatementUtils.d.ts +2 -2
- package/dist/analyzer/importStatementUtils.js.map +1 -1
- package/dist/analyzer/namedTuples.js +3 -6
- package/dist/analyzer/namedTuples.js.map +1 -1
- package/dist/analyzer/operations.d.ts +16 -0
- package/dist/analyzer/operations.js +749 -0
- package/dist/analyzer/operations.js.map +1 -0
- package/dist/analyzer/parseTreeUtils.d.ts +4 -2
- package/dist/analyzer/parseTreeUtils.js +32 -1
- package/dist/analyzer/parseTreeUtils.js.map +1 -1
- package/dist/analyzer/patternMatching.js +16 -0
- package/dist/analyzer/patternMatching.js.map +1 -1
- package/dist/analyzer/program.d.ts +11 -33
- package/dist/analyzer/program.js +73 -735
- package/dist/analyzer/program.js.map +1 -1
- package/dist/analyzer/protocols.js +1 -1
- package/dist/analyzer/protocols.js.map +1 -1
- package/dist/analyzer/service.d.ts +5 -21
- package/dist/analyzer/service.js +26 -33
- package/dist/analyzer/service.js.map +1 -1
- package/dist/analyzer/sourceFile.d.ts +9 -41
- package/dist/analyzer/sourceFile.js +219 -238
- package/dist/analyzer/sourceFile.js.map +1 -1
- package/dist/analyzer/sourceFileInfoUtils.d.ts +3 -9
- package/dist/analyzer/sourceFileInfoUtils.js.map +1 -1
- package/dist/analyzer/symbol.d.ts +3 -1
- package/dist/analyzer/symbol.js +5 -0
- package/dist/analyzer/symbol.js.map +1 -1
- package/dist/analyzer/typeEvaluator.js +460 -1425
- package/dist/analyzer/typeEvaluator.js.map +1 -1
- package/dist/analyzer/typeEvaluatorTypes.d.ts +42 -7
- package/dist/analyzer/typeEvaluatorTypes.js +33 -1
- package/dist/analyzer/typeEvaluatorTypes.js.map +1 -1
- package/dist/analyzer/typeGuards.js +2 -8
- package/dist/analyzer/typeGuards.js.map +1 -1
- package/dist/analyzer/typePrinter.d.ts +3 -3
- package/dist/analyzer/typePrinter.js +247 -100
- package/dist/analyzer/typePrinter.js.map +1 -1
- package/dist/analyzer/typeUtils.d.ts +14 -7
- package/dist/analyzer/typeUtils.js +204 -49
- package/dist/analyzer/typeUtils.js.map +1 -1
- package/dist/analyzer/typeVarContext.d.ts +6 -7
- package/dist/analyzer/typeVarContext.js +21 -32
- package/dist/analyzer/typeVarContext.js.map +1 -1
- package/dist/analyzer/typedDicts.js +2 -2
- package/dist/analyzer/typedDicts.js.map +1 -1
- package/dist/analyzer/types.d.ts +7 -4
- package/dist/analyzer/types.js +20 -10
- package/dist/analyzer/types.js.map +1 -1
- package/dist/backgroundAnalysisBase.d.ts +1 -1
- package/dist/backgroundAnalysisBase.js +16 -0
- package/dist/backgroundAnalysisBase.js.map +1 -1
- package/dist/commands/dumpFileDebugInfoCommand.js +0 -1
- package/dist/commands/dumpFileDebugInfoCommand.js.map +1 -1
- package/dist/common/extensibility.d.ts +28 -4
- package/dist/common/extensibility.js.map +1 -1
- package/dist/common/logTracker.d.ts +2 -0
- package/dist/common/logTracker.js +8 -1
- package/dist/common/logTracker.js.map +1 -1
- package/dist/common/lspUtils.d.ts +4 -1
- package/dist/common/lspUtils.js +38 -1
- package/dist/common/lspUtils.js.map +1 -1
- package/dist/common/pathUtils.d.ts +11 -11
- package/dist/common/pathUtils.js.map +1 -1
- package/dist/common/pythonVersion.d.ts +2 -1
- package/dist/common/pythonVersion.js +1 -0
- package/dist/common/pythonVersion.js.map +1 -1
- package/dist/common/workspaceEditUtils.d.ts +8 -8
- package/dist/common/workspaceEditUtils.js +10 -10
- package/dist/common/workspaceEditUtils.js.map +1 -1
- package/dist/languageServerBase.d.ts +3 -7
- package/dist/languageServerBase.js +41 -73
- package/dist/languageServerBase.js.map +1 -1
- package/dist/languageService/autoImporter.d.ts +50 -51
- package/dist/languageService/autoImporter.js +125 -210
- package/dist/languageService/autoImporter.js.map +1 -1
- package/dist/languageService/callHierarchyProvider.d.ts +1 -1
- package/dist/languageService/callHierarchyProvider.js +11 -37
- package/dist/languageService/callHierarchyProvider.js.map +1 -1
- package/dist/languageService/completionProvider.d.ts +39 -81
- package/dist/languageService/completionProvider.js +572 -801
- package/dist/languageService/completionProvider.js.map +1 -1
- package/dist/languageService/documentHighlightProvider.js +1 -1
- package/dist/languageService/documentHighlightProvider.js.map +1 -1
- package/dist/languageService/documentSymbolCollector.d.ts +6 -7
- package/dist/languageService/documentSymbolCollector.js +47 -28
- package/dist/languageService/documentSymbolCollector.js.map +1 -1
- package/dist/languageService/documentSymbolProvider.d.ts +13 -35
- package/dist/languageService/documentSymbolProvider.js +52 -264
- package/dist/languageService/documentSymbolProvider.js.map +1 -1
- package/dist/languageService/hoverProvider.d.ts +5 -6
- package/dist/languageService/hoverProvider.js +40 -132
- package/dist/languageService/hoverProvider.js.map +1 -1
- package/dist/languageService/referencesProvider.d.ts +6 -11
- package/dist/languageService/referencesProvider.js +23 -17
- package/dist/languageService/referencesProvider.js.map +1 -1
- package/dist/languageService/renameProvider.d.ts +16 -0
- package/dist/languageService/renameProvider.js +139 -0
- package/dist/languageService/renameProvider.js.map +1 -0
- package/dist/languageService/symbolIndexer.d.ts +31 -0
- package/dist/languageService/symbolIndexer.js +105 -0
- package/dist/languageService/symbolIndexer.js.map +1 -0
- package/dist/languageService/tooltipUtils.d.ts +8 -1
- package/dist/languageService/tooltipUtils.js +102 -1
- package/dist/languageService/tooltipUtils.js.map +1 -1
- package/dist/languageService/workspaceSymbolProvider.d.ts +17 -0
- package/dist/languageService/workspaceSymbolProvider.js +133 -0
- package/dist/languageService/workspaceSymbolProvider.js.map +1 -0
- package/dist/localization/localize.d.ts +33 -15
- package/dist/localization/localize.js +13 -7
- package/dist/localization/localize.js.map +1 -1
- package/dist/localization/package.nls.en-us.json +14 -7
- package/dist/parser/parser.js +3 -0
- package/dist/parser/parser.js.map +1 -1
- package/dist/pyright.js +26 -4
- package/dist/pyright.js.map +1 -1
- package/dist/tests/chainedSourceFiles.test.js +15 -20
- package/dist/tests/chainedSourceFiles.test.js.map +1 -1
- package/dist/tests/checker.test.js +14 -0
- package/dist/tests/checker.test.js.map +1 -1
- package/dist/tests/completions.test.js +11 -236
- package/dist/tests/completions.test.js.map +1 -1
- package/dist/tests/docStringConversion.test.js +36 -2
- package/dist/tests/docStringConversion.test.js.map +1 -1
- package/dist/tests/documentSymbolCollector.test.js +3 -3
- package/dist/tests/documentSymbolCollector.test.js.map +1 -1
- package/dist/tests/fourslash/completions.override2.fourslash.js +1 -16
- package/dist/tests/fourslash/completions.override2.fourslash.js.map +1 -1
- package/dist/tests/fourslash/fourslash.d.ts +4 -4
- package/dist/tests/fourslash/missingTypeStub.codeAction.fourslash.js +1 -1
- package/dist/tests/fourslash/missingTypeStub.codeAction.fourslash.js.map +1 -1
- package/dist/tests/harness/fourslash/testState.d.ts +17 -11
- package/dist/tests/harness/fourslash/testState.js +39 -50
- package/dist/tests/harness/fourslash/testState.js.map +1 -1
- package/dist/tests/importResolver.test.js +81 -1
- package/dist/tests/importResolver.test.js.map +1 -1
- package/dist/tests/sourceFile.test.js +1 -1
- package/dist/tests/sourceFile.test.js.map +1 -1
- package/dist/tests/testStateUtils.d.ts +2 -2
- package/dist/tests/testStateUtils.js +38 -8
- package/dist/tests/testStateUtils.js.map +1 -1
- package/dist/tests/typeEvaluator2.test.js +13 -1
- package/dist/tests/typeEvaluator2.test.js.map +1 -1
- package/dist/tests/typeEvaluator3.test.js +5 -1
- package/dist/tests/typeEvaluator3.test.js.map +1 -1
- package/dist/tests/typeEvaluator4.test.js +9 -1
- package/dist/tests/typeEvaluator4.test.js.map +1 -1
- package/dist/tests/typeEvaluator5.test.js +25 -9
- package/dist/tests/typeEvaluator5.test.js.map +1 -1
- package/dist/tests/workspaceEditUtils.test.js +95 -6
- package/dist/tests/workspaceEditUtils.test.js.map +1 -1
- package/package.json +4 -4
- package/dist/languageService/importAdder.d.ts +0 -40
- package/dist/languageService/importAdder.js +0 -388
- package/dist/languageService/importAdder.js.map +0 -1
- package/dist/languageService/indentationUtils.d.ts +0 -16
- package/dist/languageService/indentationUtils.js +0 -727
- package/dist/languageService/indentationUtils.js.map +0 -1
- package/dist/languageService/insertionPointUtils.d.ts +0 -9
- package/dist/languageService/insertionPointUtils.js +0 -132
- package/dist/languageService/insertionPointUtils.js.map +0 -1
- package/dist/languageService/renameModuleProvider.d.ts +0 -65
- package/dist/languageService/renameModuleProvider.js +0 -939
- package/dist/languageService/renameModuleProvider.js.map +0 -1
- package/dist/tests/fourslash/completions.commitChars.fourslash.d.ts +0 -1
- package/dist/tests/fourslash/completions.commitChars.fourslash.js +0 -81
- package/dist/tests/fourslash/completions.commitChars.fourslash.js.map +0 -1
- package/dist/tests/importAdder.test.d.ts +0 -1
- package/dist/tests/importAdder.test.js +0 -1325
- package/dist/tests/importAdder.test.js.map +0 -1
- package/dist/tests/indentationUtils.ptvs.test.d.ts +0 -1
- package/dist/tests/indentationUtils.ptvs.test.js +0 -324
- package/dist/tests/indentationUtils.ptvs.test.js.map +0 -1
- package/dist/tests/indentationUtils.reindent.test.d.ts +0 -1
- package/dist/tests/indentationUtils.reindent.test.js +0 -372
- package/dist/tests/indentationUtils.reindent.test.js.map +0 -1
- package/dist/tests/indentationUtils.test.d.ts +0 -1
- package/dist/tests/indentationUtils.test.js +0 -502
- package/dist/tests/indentationUtils.test.js.map +0 -1
- package/dist/tests/insertionPointUtils.test.d.ts +0 -1
- package/dist/tests/insertionPointUtils.test.js +0 -154
- package/dist/tests/insertionPointUtils.test.js.map +0 -1
- package/dist/tests/moveSymbol.importAdder.test.d.ts +0 -1
- package/dist/tests/moveSymbol.importAdder.test.js +0 -298
- package/dist/tests/moveSymbol.importAdder.test.js.map +0 -1
- package/dist/tests/moveSymbol.insertion.test.d.ts +0 -1
- package/dist/tests/moveSymbol.insertion.test.js +0 -537
- package/dist/tests/moveSymbol.insertion.test.js.map +0 -1
- package/dist/tests/moveSymbol.misc.test.d.ts +0 -1
- package/dist/tests/moveSymbol.misc.test.js +0 -169
- package/dist/tests/moveSymbol.misc.test.js.map +0 -1
- package/dist/tests/moveSymbol.updateReference.test.d.ts +0 -1
- package/dist/tests/moveSymbol.updateReference.test.js +0 -1071
- package/dist/tests/moveSymbol.updateReference.test.js.map +0 -1
- package/dist/tests/renameModule.folder.test.d.ts +0 -1
- package/dist/tests/renameModule.folder.test.js +0 -229
- package/dist/tests/renameModule.folder.test.js.map +0 -1
- package/dist/tests/renameModule.fromImports.test.d.ts +0 -1
- package/dist/tests/renameModule.fromImports.test.js +0 -790
- package/dist/tests/renameModule.fromImports.test.js.map +0 -1
- package/dist/tests/renameModule.imports.test.d.ts +0 -1
- package/dist/tests/renameModule.imports.test.js +0 -380
- package/dist/tests/renameModule.imports.test.js.map +0 -1
- package/dist/tests/renameModule.misc.test.d.ts +0 -1
- package/dist/tests/renameModule.misc.test.js +0 -615
- package/dist/tests/renameModule.misc.test.js.map +0 -1
- package/dist/tests/renameModule.relativePath.test.d.ts +0 -1
- package/dist/tests/renameModule.relativePath.test.js +0 -231
- package/dist/tests/renameModule.relativePath.test.js.map +0 -1
- package/dist/tests/renameModuleTestUtils.d.ts +0 -4
- package/dist/tests/renameModuleTestUtils.js +0 -76
- package/dist/tests/renameModuleTestUtils.js.map +0 -1
@@ -0,0 +1,749 @@
|
|
1
|
+
"use strict";
|
2
|
+
/*
|
3
|
+
* operations.ts
|
4
|
+
* Copyright (c) Microsoft Corporation.
|
5
|
+
* Licensed under the MIT license.
|
6
|
+
* Author: Eric Traut
|
7
|
+
*
|
8
|
+
* Provides type evaluation logic for unary, binary, augmented assignment,
|
9
|
+
* and ternary operators.
|
10
|
+
*/
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
12
|
+
exports.getTypeOfTernaryOperation = exports.getTypeOfUnaryOperation = exports.getTypeOfAugmentedAssignment = exports.getTypeOfBinaryOperation = exports.validateBinaryOperation = void 0;
|
13
|
+
const diagnostic_1 = require("../common/diagnostic");
|
14
|
+
const diagnosticRules_1 = require("../common/diagnosticRules");
|
15
|
+
const pythonVersion_1 = require("../common/pythonVersion");
|
16
|
+
const localize_1 = require("../localization/localize");
|
17
|
+
const analyzerNodeInfo_1 = require("./analyzerNodeInfo");
|
18
|
+
const parseTreeUtils_1 = require("./parseTreeUtils");
|
19
|
+
const staticExpressions_1 = require("./staticExpressions");
|
20
|
+
const typeUtils_1 = require("./typeUtils");
|
21
|
+
const types_1 = require("./types");
|
22
|
+
// Maps binary operators to the magic methods that implement them.
|
23
|
+
const binaryOperatorMap = {
|
24
|
+
[0 /* Add */]: ['__add__', '__radd__'],
|
25
|
+
[33 /* Subtract */]: ['__sub__', '__rsub__'],
|
26
|
+
[26 /* Multiply */]: ['__mul__', '__rmul__'],
|
27
|
+
[13 /* FloorDivide */]: ['__floordiv__', '__rfloordiv__'],
|
28
|
+
[10 /* Divide */]: ['__truediv__', '__rtruediv__'],
|
29
|
+
[24 /* Mod */]: ['__mod__', '__rmod__'],
|
30
|
+
[29 /* Power */]: ['__pow__', '__rpow__'],
|
31
|
+
[22 /* MatrixMultiply */]: ['__matmul__', '__rmatmul__'],
|
32
|
+
[3 /* BitwiseAnd */]: ['__and__', '__rand__'],
|
33
|
+
[6 /* BitwiseOr */]: ['__or__', '__ror__'],
|
34
|
+
[8 /* BitwiseXor */]: ['__xor__', '__rxor__'],
|
35
|
+
[17 /* LeftShift */]: ['__lshift__', '__rlshift__'],
|
36
|
+
[31 /* RightShift */]: ['__rshift__', '__rrshift__'],
|
37
|
+
[12 /* Equals */]: ['__eq__', '__eq__'],
|
38
|
+
[28 /* NotEquals */]: ['__ne__', '__ne__'],
|
39
|
+
[20 /* LessThan */]: ['__lt__', '__gt__'],
|
40
|
+
[21 /* LessThanOrEqual */]: ['__le__', '__ge__'],
|
41
|
+
[15 /* GreaterThan */]: ['__gt__', '__lt__'],
|
42
|
+
[16 /* GreaterThanOrEqual */]: ['__ge__', '__le__'],
|
43
|
+
};
|
44
|
+
// Map of operators that always return a bool result.
|
45
|
+
const booleanOperatorMap = {
|
46
|
+
[36 /* And */]: true,
|
47
|
+
[37 /* Or */]: true,
|
48
|
+
[39 /* Is */]: true,
|
49
|
+
[40 /* IsNot */]: true,
|
50
|
+
[41 /* In */]: true,
|
51
|
+
[42 /* NotIn */]: true,
|
52
|
+
};
|
53
|
+
// If the number of subtypes starts to explode when applying "literal math",
|
54
|
+
// cut off the literal union and fall back to the non-literal supertype.
|
55
|
+
const maxLiteralMathSubtypeCount = 64;
|
56
|
+
function validateBinaryOperation(evaluator, operator, leftTypeResult, rightTypeResult, errorNode, inferenceContext, diag, options) {
|
57
|
+
const leftType = leftTypeResult.type;
|
58
|
+
const rightType = rightTypeResult.type;
|
59
|
+
let type;
|
60
|
+
let concreteLeftType = evaluator.makeTopLevelTypeVarsConcrete(leftType);
|
61
|
+
if (booleanOperatorMap[operator] !== undefined) {
|
62
|
+
// If it's an AND or OR, we need to handle short-circuiting by
|
63
|
+
// eliminating any known-truthy or known-falsy types.
|
64
|
+
if (operator === 36 /* And */) {
|
65
|
+
// If the LHS evaluates to falsy, the And expression will
|
66
|
+
// always return the type of the left-hand side.
|
67
|
+
if (!evaluator.canBeTruthy(concreteLeftType)) {
|
68
|
+
return leftType;
|
69
|
+
}
|
70
|
+
// If the LHS evaluates to truthy, the And expression will
|
71
|
+
// always return the type of the right-hand side.
|
72
|
+
if (!evaluator.canBeFalsy(concreteLeftType)) {
|
73
|
+
return rightType;
|
74
|
+
}
|
75
|
+
concreteLeftType = evaluator.removeTruthinessFromType(concreteLeftType);
|
76
|
+
if ((0, types_1.isNever)(rightType)) {
|
77
|
+
return concreteLeftType;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
else if (operator === 37 /* Or */) {
|
81
|
+
// If the LHS evaluates to truthy, the Or expression will
|
82
|
+
// always return the type of the left-hand side.
|
83
|
+
if (!evaluator.canBeFalsy(concreteLeftType)) {
|
84
|
+
return leftType;
|
85
|
+
}
|
86
|
+
// If the LHS evaluates to falsy, the Or expression will
|
87
|
+
// always return the type of the right-hand side.
|
88
|
+
if (!evaluator.canBeTruthy(concreteLeftType)) {
|
89
|
+
return rightType;
|
90
|
+
}
|
91
|
+
concreteLeftType = evaluator.removeFalsinessFromType(concreteLeftType);
|
92
|
+
if ((0, types_1.isNever)(rightType)) {
|
93
|
+
return concreteLeftType;
|
94
|
+
}
|
95
|
+
}
|
96
|
+
if ((0, types_1.isNever)(leftType) || (0, types_1.isNever)(rightType)) {
|
97
|
+
return types_1.NeverType.createNever();
|
98
|
+
}
|
99
|
+
// The "in" and "not in" operators make use of the __contains__
|
100
|
+
// magic method.
|
101
|
+
if (operator === 41 /* In */ || operator === 42 /* NotIn */) {
|
102
|
+
type = evaluator.mapSubtypesExpandTypeVars(rightType,
|
103
|
+
/* conditionFilter */ undefined, (rightSubtypeExpanded, rightSubtypeUnexpanded) => {
|
104
|
+
return evaluator.mapSubtypesExpandTypeVars(concreteLeftType, (0, typeUtils_1.getTypeCondition)(rightSubtypeExpanded), (leftSubtype) => {
|
105
|
+
var _a;
|
106
|
+
if ((0, types_1.isAnyOrUnknown)(leftSubtype) || (0, types_1.isAnyOrUnknown)(rightSubtypeUnexpanded)) {
|
107
|
+
return (0, typeUtils_1.preserveUnknown)(leftSubtype, rightSubtypeExpanded);
|
108
|
+
}
|
109
|
+
let returnType = evaluator.getTypeOfMagicMethodReturn(rightSubtypeExpanded, [{ type: leftSubtype, isIncomplete: leftTypeResult.isIncomplete }], '__contains__', errorNode,
|
110
|
+
/* inferenceContext */ undefined);
|
111
|
+
if (!returnType) {
|
112
|
+
// If __contains__ was not supported, fall back
|
113
|
+
// on an iterable.
|
114
|
+
const iteratorType = (_a = evaluator.getTypeOfIterator({ type: rightSubtypeExpanded, isIncomplete: rightTypeResult.isIncomplete },
|
115
|
+
/* isAsync */ false,
|
116
|
+
/* errorNode */ undefined)) === null || _a === void 0 ? void 0 : _a.type;
|
117
|
+
if (iteratorType && evaluator.assignType(iteratorType, leftSubtype)) {
|
118
|
+
returnType = evaluator.getBuiltInObject(errorNode, 'bool');
|
119
|
+
}
|
120
|
+
}
|
121
|
+
if (!returnType) {
|
122
|
+
diag.addMessage(localize_1.Localizer.Diagnostic.typeNotSupportBinaryOperator().format({
|
123
|
+
operator: (0, parseTreeUtils_1.printOperator)(operator),
|
124
|
+
leftType: evaluator.printType(leftSubtype),
|
125
|
+
rightType: evaluator.printType(rightSubtypeExpanded),
|
126
|
+
}));
|
127
|
+
}
|
128
|
+
return returnType;
|
129
|
+
});
|
130
|
+
});
|
131
|
+
// Assume that a bool is returned even if the type is unknown
|
132
|
+
if (type && !(0, types_1.isNever)(type)) {
|
133
|
+
type = evaluator.getBuiltInObject(errorNode, 'bool');
|
134
|
+
}
|
135
|
+
}
|
136
|
+
else {
|
137
|
+
type = evaluator.mapSubtypesExpandTypeVars(concreteLeftType,
|
138
|
+
/* conditionFilter */ undefined, (leftSubtypeExpanded, leftSubtypeUnexpanded) => {
|
139
|
+
return evaluator.mapSubtypesExpandTypeVars(rightType, (0, typeUtils_1.getTypeCondition)(leftSubtypeExpanded), (rightSubtypeExpanded, rightSubtypeUnexpanded) => {
|
140
|
+
// If the operator is an AND or OR, we need to combine the two types.
|
141
|
+
if (operator === 36 /* And */ || operator === 37 /* Or */) {
|
142
|
+
return (0, types_1.combineTypes)([leftSubtypeUnexpanded, rightSubtypeUnexpanded]);
|
143
|
+
}
|
144
|
+
// The other boolean operators always return a bool value.
|
145
|
+
return evaluator.getBuiltInObject(errorNode, 'bool');
|
146
|
+
});
|
147
|
+
});
|
148
|
+
}
|
149
|
+
}
|
150
|
+
else if (binaryOperatorMap[operator]) {
|
151
|
+
if ((0, types_1.isNever)(leftType) || (0, types_1.isNever)(rightType)) {
|
152
|
+
return types_1.NeverType.createNever();
|
153
|
+
}
|
154
|
+
// Handle certain operations on certain homogenous literal types
|
155
|
+
// using special-case math. For example, Literal[1, 2] + Literal[3, 4]
|
156
|
+
// should result in Literal[4, 5, 6].
|
157
|
+
if (options.isLiteralMathAllowed) {
|
158
|
+
const leftLiteralClassName = (0, typeUtils_1.getLiteralTypeClassName)(leftType);
|
159
|
+
if (leftLiteralClassName && !(0, typeUtils_1.getTypeCondition)(leftType)) {
|
160
|
+
const rightLiteralClassName = (0, typeUtils_1.getLiteralTypeClassName)(rightType);
|
161
|
+
if (leftLiteralClassName === rightLiteralClassName &&
|
162
|
+
!(0, typeUtils_1.getTypeCondition)(rightType) &&
|
163
|
+
(0, typeUtils_1.getUnionSubtypeCount)(leftType) * (0, typeUtils_1.getUnionSubtypeCount)(rightType) < maxLiteralMathSubtypeCount) {
|
164
|
+
if (leftLiteralClassName === 'str' || leftLiteralClassName === 'bytes') {
|
165
|
+
if (operator === 0 /* Add */) {
|
166
|
+
type = (0, typeUtils_1.mapSubtypes)(leftType, (leftSubtype) => {
|
167
|
+
return (0, typeUtils_1.mapSubtypes)(rightType, (rightSubtype) => {
|
168
|
+
const leftClassSubtype = leftSubtype;
|
169
|
+
const rightClassSubtype = rightSubtype;
|
170
|
+
return types_1.ClassType.cloneWithLiteral(leftClassSubtype, (leftClassSubtype.literalValue +
|
171
|
+
rightClassSubtype.literalValue));
|
172
|
+
});
|
173
|
+
});
|
174
|
+
}
|
175
|
+
}
|
176
|
+
else if (leftLiteralClassName === 'int') {
|
177
|
+
if (operator === 0 /* Add */ ||
|
178
|
+
operator === 33 /* Subtract */ ||
|
179
|
+
operator === 26 /* Multiply */ ||
|
180
|
+
operator === 13 /* FloorDivide */ ||
|
181
|
+
operator === 24 /* Mod */) {
|
182
|
+
let isValidResult = true;
|
183
|
+
type = (0, typeUtils_1.mapSubtypes)(leftType, (leftSubtype) => {
|
184
|
+
return (0, typeUtils_1.mapSubtypes)(rightType, (rightSubtype) => {
|
185
|
+
try {
|
186
|
+
const leftClassSubtype = leftSubtype;
|
187
|
+
const rightClassSubtype = rightSubtype;
|
188
|
+
const leftLiteralValue = BigInt(leftClassSubtype.literalValue);
|
189
|
+
const rightLiteralValue = BigInt(rightClassSubtype.literalValue);
|
190
|
+
let newValue;
|
191
|
+
if (operator === 0 /* Add */) {
|
192
|
+
newValue = leftLiteralValue + rightLiteralValue;
|
193
|
+
}
|
194
|
+
else if (operator === 33 /* Subtract */) {
|
195
|
+
newValue = leftLiteralValue - rightLiteralValue;
|
196
|
+
}
|
197
|
+
else if (operator === 26 /* Multiply */) {
|
198
|
+
newValue = leftLiteralValue * rightLiteralValue;
|
199
|
+
}
|
200
|
+
else if (operator === 13 /* FloorDivide */) {
|
201
|
+
if (rightLiteralValue !== BigInt(0)) {
|
202
|
+
newValue = leftLiteralValue / rightLiteralValue;
|
203
|
+
}
|
204
|
+
}
|
205
|
+
else if (operator === 24 /* Mod */) {
|
206
|
+
if (rightLiteralValue !== BigInt(0)) {
|
207
|
+
newValue = leftLiteralValue % rightLiteralValue;
|
208
|
+
}
|
209
|
+
}
|
210
|
+
if (newValue === undefined) {
|
211
|
+
isValidResult = false;
|
212
|
+
return undefined;
|
213
|
+
}
|
214
|
+
else if (typeof newValue === 'number' && isNaN(newValue)) {
|
215
|
+
isValidResult = false;
|
216
|
+
return undefined;
|
217
|
+
}
|
218
|
+
else {
|
219
|
+
// Convert back to a simple number if it fits. Leave as a bigint
|
220
|
+
// if it doesn't.
|
221
|
+
if (newValue >= Number.MIN_SAFE_INTEGER &&
|
222
|
+
newValue <= Number.MAX_SAFE_INTEGER) {
|
223
|
+
newValue = Number(newValue);
|
224
|
+
}
|
225
|
+
return types_1.ClassType.cloneWithLiteral(leftClassSubtype, newValue);
|
226
|
+
}
|
227
|
+
}
|
228
|
+
catch {
|
229
|
+
isValidResult = false;
|
230
|
+
return undefined;
|
231
|
+
}
|
232
|
+
});
|
233
|
+
});
|
234
|
+
if (!isValidResult) {
|
235
|
+
type = undefined;
|
236
|
+
}
|
237
|
+
}
|
238
|
+
}
|
239
|
+
}
|
240
|
+
}
|
241
|
+
}
|
242
|
+
if (!type) {
|
243
|
+
type = evaluator.mapSubtypesExpandTypeVars(leftType,
|
244
|
+
/* conditionFilter */ undefined, (leftSubtypeExpanded, leftSubtypeUnexpanded) => {
|
245
|
+
return evaluator.mapSubtypesExpandTypeVars(rightType, (0, typeUtils_1.getTypeCondition)(leftSubtypeExpanded), (rightSubtypeExpanded, rightSubtypeUnexpanded) => {
|
246
|
+
if ((0, types_1.isAnyOrUnknown)(leftSubtypeUnexpanded) || (0, types_1.isAnyOrUnknown)(rightSubtypeUnexpanded)) {
|
247
|
+
return (0, typeUtils_1.preserveUnknown)(leftSubtypeUnexpanded, rightSubtypeUnexpanded);
|
248
|
+
}
|
249
|
+
const tupleClassType = evaluator.getTupleClassType();
|
250
|
+
// Special-case __add__ for tuples when the types for both tuples are known.
|
251
|
+
if (options.isTupleAddAllowed &&
|
252
|
+
operator === 0 /* Add */ &&
|
253
|
+
(0, types_1.isClassInstance)(leftSubtypeExpanded) &&
|
254
|
+
(0, typeUtils_1.isTupleClass)(leftSubtypeExpanded) &&
|
255
|
+
leftSubtypeExpanded.tupleTypeArguments &&
|
256
|
+
!(0, typeUtils_1.isUnboundedTupleClass)(leftSubtypeExpanded) &&
|
257
|
+
(0, types_1.isClassInstance)(rightSubtypeExpanded) &&
|
258
|
+
(0, typeUtils_1.isTupleClass)(rightSubtypeExpanded) &&
|
259
|
+
rightSubtypeExpanded.tupleTypeArguments &&
|
260
|
+
!(0, typeUtils_1.isUnboundedTupleClass)(rightSubtypeExpanded) &&
|
261
|
+
tupleClassType &&
|
262
|
+
(0, types_1.isInstantiableClass)(tupleClassType)) {
|
263
|
+
return types_1.ClassType.cloneAsInstance((0, typeUtils_1.specializeTupleClass)(tupleClassType, [
|
264
|
+
...leftSubtypeExpanded.tupleTypeArguments,
|
265
|
+
...rightSubtypeExpanded.tupleTypeArguments,
|
266
|
+
]));
|
267
|
+
}
|
268
|
+
const magicMethodName = binaryOperatorMap[operator][0];
|
269
|
+
let resultType = evaluator.getTypeOfMagicMethodReturn(convertFunctionToObject(evaluator, leftSubtypeUnexpanded), [{ type: rightSubtypeUnexpanded, isIncomplete: rightTypeResult.isIncomplete }], magicMethodName, errorNode, inferenceContext);
|
270
|
+
if (!resultType && leftSubtypeUnexpanded !== leftSubtypeExpanded) {
|
271
|
+
// Try the expanded left type.
|
272
|
+
resultType = evaluator.getTypeOfMagicMethodReturn(convertFunctionToObject(evaluator, leftSubtypeExpanded), [{ type: rightSubtypeUnexpanded, isIncomplete: rightTypeResult.isIncomplete }], magicMethodName, errorNode, inferenceContext);
|
273
|
+
}
|
274
|
+
if (!resultType && rightSubtypeUnexpanded !== rightSubtypeExpanded) {
|
275
|
+
// Try the expanded left and right type.
|
276
|
+
resultType = evaluator.getTypeOfMagicMethodReturn(convertFunctionToObject(evaluator, leftSubtypeExpanded), [{ type: rightSubtypeExpanded, isIncomplete: rightTypeResult.isIncomplete }], magicMethodName, errorNode, inferenceContext);
|
277
|
+
}
|
278
|
+
if (!resultType) {
|
279
|
+
// Try the alternate form (swapping right and left).
|
280
|
+
const altMagicMethodName = binaryOperatorMap[operator][1];
|
281
|
+
resultType = evaluator.getTypeOfMagicMethodReturn(convertFunctionToObject(evaluator, rightSubtypeUnexpanded), [{ type: leftSubtypeUnexpanded, isIncomplete: leftTypeResult.isIncomplete }], altMagicMethodName, errorNode, inferenceContext);
|
282
|
+
if (!resultType && rightSubtypeUnexpanded !== rightSubtypeExpanded) {
|
283
|
+
// Try the expanded right type.
|
284
|
+
resultType = evaluator.getTypeOfMagicMethodReturn(convertFunctionToObject(evaluator, rightSubtypeExpanded), [
|
285
|
+
{
|
286
|
+
type: leftSubtypeUnexpanded,
|
287
|
+
isIncomplete: leftTypeResult.isIncomplete,
|
288
|
+
},
|
289
|
+
], altMagicMethodName, errorNode, inferenceContext);
|
290
|
+
}
|
291
|
+
if (!resultType && leftSubtypeUnexpanded !== leftSubtypeExpanded) {
|
292
|
+
// Try the expanded right and left type.
|
293
|
+
resultType = evaluator.getTypeOfMagicMethodReturn(convertFunctionToObject(evaluator, rightSubtypeExpanded), [{ type: leftSubtypeExpanded, isIncomplete: leftTypeResult.isIncomplete }], altMagicMethodName, errorNode, inferenceContext);
|
294
|
+
}
|
295
|
+
}
|
296
|
+
if (!resultType) {
|
297
|
+
if (inferenceContext) {
|
298
|
+
diag.addMessage(localize_1.Localizer.Diagnostic.typeNotSupportBinaryOperatorBidirectional().format({
|
299
|
+
operator: (0, parseTreeUtils_1.printOperator)(operator),
|
300
|
+
leftType: evaluator.printType(leftSubtypeExpanded),
|
301
|
+
rightType: evaluator.printType(rightSubtypeExpanded),
|
302
|
+
expectedType: evaluator.printType(inferenceContext.expectedType),
|
303
|
+
}));
|
304
|
+
}
|
305
|
+
else {
|
306
|
+
diag.addMessage(localize_1.Localizer.Diagnostic.typeNotSupportBinaryOperator().format({
|
307
|
+
operator: (0, parseTreeUtils_1.printOperator)(operator),
|
308
|
+
leftType: evaluator.printType(leftSubtypeExpanded),
|
309
|
+
rightType: evaluator.printType(rightSubtypeExpanded),
|
310
|
+
}));
|
311
|
+
}
|
312
|
+
}
|
313
|
+
return resultType;
|
314
|
+
});
|
315
|
+
});
|
316
|
+
}
|
317
|
+
}
|
318
|
+
return type && (0, types_1.isNever)(type) ? undefined : type;
|
319
|
+
}
|
320
|
+
exports.validateBinaryOperation = validateBinaryOperation;
|
321
|
+
function getTypeOfBinaryOperation(evaluator, node, inferenceContext, flags) {
|
322
|
+
const leftExpression = node.leftExpression;
|
323
|
+
let rightExpression = node.rightExpression;
|
324
|
+
let isIncomplete = false;
|
325
|
+
let typeErrors = false;
|
326
|
+
// If this is a comparison and the left expression is also a comparison,
|
327
|
+
// we need to change the behavior to accommodate python's "chained
|
328
|
+
// comparisons" feature.
|
329
|
+
if ((0, parseTreeUtils_1.operatorSupportsChaining)(node.operator)) {
|
330
|
+
if (rightExpression.nodeType === 7 /* BinaryOperation */ &&
|
331
|
+
!rightExpression.parenthesized &&
|
332
|
+
(0, parseTreeUtils_1.operatorSupportsChaining)(rightExpression.operator)) {
|
333
|
+
// Evaluate the right expression so it is type checked.
|
334
|
+
getTypeOfBinaryOperation(evaluator, rightExpression, inferenceContext, flags);
|
335
|
+
// Use the left side of the right expression for comparison purposes.
|
336
|
+
rightExpression = rightExpression.leftExpression;
|
337
|
+
}
|
338
|
+
}
|
339
|
+
// For most binary operations, the "expected type" is applied to the output
|
340
|
+
// of the magic method for that operation. However, the "or" and "and" operators
|
341
|
+
// have no magic method, so we apply the expected type directly to both operands.
|
342
|
+
let expectedOperandType = node.operator === 37 /* Or */ || node.operator === 36 /* And */
|
343
|
+
? inferenceContext === null || inferenceContext === void 0 ? void 0 : inferenceContext.expectedType
|
344
|
+
: undefined;
|
345
|
+
// Handle the very special case where the expected type is a list
|
346
|
+
// and the operator is a multiply. This comes up in the common case
|
347
|
+
// of "x: List[Optional[X]] = [None] * y" where y is an integer literal.
|
348
|
+
let expectedLeftOperandType;
|
349
|
+
if (node.operator === 26 /* Multiply */ &&
|
350
|
+
inferenceContext &&
|
351
|
+
(0, types_1.isClassInstance)(inferenceContext.expectedType) &&
|
352
|
+
types_1.ClassType.isBuiltIn(inferenceContext.expectedType, 'list') &&
|
353
|
+
inferenceContext.expectedType.typeArguments &&
|
354
|
+
inferenceContext.expectedType.typeArguments.length >= 1 &&
|
355
|
+
node.leftExpression.nodeType === 31 /* List */) {
|
356
|
+
expectedLeftOperandType = inferenceContext.expectedType;
|
357
|
+
}
|
358
|
+
const effectiveExpectedType = expectedOperandType !== null && expectedOperandType !== void 0 ? expectedOperandType : expectedLeftOperandType;
|
359
|
+
const leftTypeResult = evaluator.getTypeOfExpression(leftExpression, flags, (0, typeUtils_1.makeInferenceContext)(effectiveExpectedType));
|
360
|
+
let leftType = leftTypeResult.type;
|
361
|
+
if (!expectedOperandType) {
|
362
|
+
if (node.operator === 37 /* Or */ || node.operator === 36 /* And */) {
|
363
|
+
// For "or" and "and", use the type of the left operand. This allows us to
|
364
|
+
// infer a better type for expressions like `x or []`.
|
365
|
+
expectedOperandType = leftType;
|
366
|
+
}
|
367
|
+
else if (node.operator === 0 /* Add */ && node.rightExpression.nodeType === 31 /* List */) {
|
368
|
+
// For the "+" operator , use this technique only if the right operand is
|
369
|
+
// a list expression. This heuristic handles the common case of `my_list + [0]`.
|
370
|
+
expectedOperandType = leftType;
|
371
|
+
}
|
372
|
+
else if (node.operator === 6 /* BitwiseOr */) {
|
373
|
+
// If this is a bitwise or ("|"), use the type of the left operand. This allows
|
374
|
+
// us to support the case where a TypedDict is being updated with a dict expression.
|
375
|
+
if ((0, types_1.isClassInstance)(leftType) && types_1.ClassType.isTypedDictClass(leftType)) {
|
376
|
+
expectedOperandType = leftType;
|
377
|
+
}
|
378
|
+
}
|
379
|
+
}
|
380
|
+
const rightTypeResult = evaluator.getTypeOfExpression(rightExpression, flags, (0, typeUtils_1.makeInferenceContext)(expectedOperandType));
|
381
|
+
let rightType = rightTypeResult.type;
|
382
|
+
if (leftTypeResult.isIncomplete || rightTypeResult.isIncomplete) {
|
383
|
+
isIncomplete = true;
|
384
|
+
}
|
385
|
+
// Is this a "|" operator used in a context where it is supposed to be
|
386
|
+
// interpreted as a union operator?
|
387
|
+
if (node.operator === 6 /* BitwiseOr */ &&
|
388
|
+
!customMetaclassSupportsMethod(leftType, '__or__') &&
|
389
|
+
!customMetaclassSupportsMethod(rightType, '__ror__')) {
|
390
|
+
let adjustedRightType = rightType;
|
391
|
+
let adjustedLeftType = leftType;
|
392
|
+
if (!(0, types_1.isNoneInstance)(leftType) && (0, types_1.isNoneInstance)(rightType)) {
|
393
|
+
// Handle the special case where "None" is being added to the union
|
394
|
+
// with something else. Even though "None" will normally be interpreted
|
395
|
+
// as the None singleton object in contexts where a type annotation isn't
|
396
|
+
// assumed, we'll allow it here.
|
397
|
+
adjustedRightType = types_1.NoneType.createType();
|
398
|
+
}
|
399
|
+
else if (!(0, types_1.isNoneInstance)(rightType) && (0, types_1.isNoneInstance)(leftType)) {
|
400
|
+
adjustedLeftType = types_1.NoneType.createType();
|
401
|
+
}
|
402
|
+
if ((0, typeUtils_1.isUnionableType)([adjustedLeftType, adjustedRightType])) {
|
403
|
+
const fileInfo = (0, analyzerNodeInfo_1.getFileInfo)(node);
|
404
|
+
const unionNotationSupported = fileInfo.isStubFile ||
|
405
|
+
(flags & 4 /* AllowForwardReferences */) !== 0 ||
|
406
|
+
fileInfo.executionEnvironment.pythonVersion >= pythonVersion_1.PythonVersion.V3_10;
|
407
|
+
if (!unionNotationSupported) {
|
408
|
+
// If the left type is Any, we can't say for sure whether this
|
409
|
+
// is an illegal syntax or a valid application of the "|" operator.
|
410
|
+
if (!(0, types_1.isAnyOrUnknown)(adjustedLeftType)) {
|
411
|
+
evaluator.addError(localize_1.Localizer.Diagnostic.unionSyntaxIllegal(), node, node.operatorToken);
|
412
|
+
}
|
413
|
+
}
|
414
|
+
if (!evaluator.validateTypeArg({ ...leftTypeResult, node: leftExpression }, { allowVariadicTypeVar: true, allowUnpackedTuples: true }) ||
|
415
|
+
!evaluator.validateTypeArg({ ...rightTypeResult, node: rightExpression }, { allowVariadicTypeVar: true, allowUnpackedTuples: true })) {
|
416
|
+
return { type: types_1.UnknownType.create() };
|
417
|
+
}
|
418
|
+
const newUnion = (0, types_1.combineTypes)([adjustedLeftType, adjustedRightType]);
|
419
|
+
if ((0, types_1.isUnion)(newUnion)) {
|
420
|
+
types_1.TypeBase.setSpecialForm(newUnion);
|
421
|
+
}
|
422
|
+
// Check for "stringified" forward reference type expressions. The "|" operator
|
423
|
+
// doesn't support these except in certain circumstances. Notably, it can't be used
|
424
|
+
// with other strings or with types that are not specialized using an index form.
|
425
|
+
if (!fileInfo.isStubFile) {
|
426
|
+
let stringNode;
|
427
|
+
let otherNode;
|
428
|
+
let otherType;
|
429
|
+
if (leftExpression.nodeType === 48 /* StringList */) {
|
430
|
+
stringNode = leftExpression;
|
431
|
+
otherNode = rightExpression;
|
432
|
+
otherType = rightType;
|
433
|
+
}
|
434
|
+
else if (rightExpression.nodeType === 48 /* StringList */) {
|
435
|
+
stringNode = rightExpression;
|
436
|
+
otherNode = leftExpression;
|
437
|
+
otherType = leftType;
|
438
|
+
}
|
439
|
+
if (stringNode && otherNode && otherType) {
|
440
|
+
let isAllowed = true;
|
441
|
+
if ((0, types_1.isClass)(otherType)) {
|
442
|
+
if (!otherType.isTypeArgumentExplicit || (0, types_1.isClassInstance)(otherType)) {
|
443
|
+
isAllowed = false;
|
444
|
+
}
|
445
|
+
}
|
446
|
+
if (!isAllowed) {
|
447
|
+
evaluator.addDiagnostic(fileInfo.diagnosticRuleSet.reportGeneralTypeIssues, diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, localize_1.Localizer.Diagnostic.unionForwardReferenceNotAllowed(), stringNode);
|
448
|
+
}
|
449
|
+
}
|
450
|
+
}
|
451
|
+
return { type: newUnion };
|
452
|
+
}
|
453
|
+
}
|
454
|
+
// Optional checks apply to all operations except for boolean operations.
|
455
|
+
let isLeftOptionalType = false;
|
456
|
+
if (booleanOperatorMap[node.operator] === undefined) {
|
457
|
+
// None is a valid operand for == and != even if the type stub says otherwise.
|
458
|
+
if (node.operator === 12 /* Equals */ || node.operator === 28 /* NotEquals */) {
|
459
|
+
leftType = (0, types_1.removeNoneFromUnion)(leftType);
|
460
|
+
}
|
461
|
+
else {
|
462
|
+
isLeftOptionalType = (0, typeUtils_1.isOptionalType)(leftType);
|
463
|
+
}
|
464
|
+
// None is a valid operand for == and != even if the type stub says otherwise.
|
465
|
+
if (node.operator === 12 /* Equals */ || node.operator === 28 /* NotEquals */) {
|
466
|
+
rightType = (0, types_1.removeNoneFromUnion)(rightType);
|
467
|
+
}
|
468
|
+
}
|
469
|
+
const diag = new diagnostic_1.DiagnosticAddendum();
|
470
|
+
// Don't use literal math if either of the operation is within a loop
|
471
|
+
// because the literal values may change each time.
|
472
|
+
const isLiteralMathAllowed = !(0, parseTreeUtils_1.isWithinLoop)(node);
|
473
|
+
// Don't special-case tuple __add__ if the left type is a union. This
|
474
|
+
// can result in an infinite loop if we keep creating new tuple types
|
475
|
+
// within a loop construct using __add__.
|
476
|
+
const isTupleAddAllowed = !(0, types_1.isUnion)(leftType);
|
477
|
+
let type = validateBinaryOperation(evaluator, node.operator, { type: leftType, isIncomplete: leftTypeResult.isIncomplete }, { type: rightType, isIncomplete: rightTypeResult.isIncomplete }, node, inferenceContext, diag, { isLiteralMathAllowed, isTupleAddAllowed });
|
478
|
+
if (!diag.isEmpty() || !type) {
|
479
|
+
typeErrors = true;
|
480
|
+
if (!isIncomplete) {
|
481
|
+
const fileInfo = (0, analyzerNodeInfo_1.getFileInfo)(node);
|
482
|
+
if (isLeftOptionalType && diag.getMessages().length === 1) {
|
483
|
+
// If the left was an optional type and there is just one diagnostic,
|
484
|
+
// assume that it was due to a "None" not being supported. Report
|
485
|
+
// this as a reportOptionalOperand diagnostic rather than a
|
486
|
+
// reportGeneralTypeIssues diagnostic.
|
487
|
+
evaluator.addDiagnostic(fileInfo.diagnosticRuleSet.reportOptionalOperand, diagnosticRules_1.DiagnosticRule.reportOptionalOperand, localize_1.Localizer.Diagnostic.noneOperator().format({
|
488
|
+
operator: (0, parseTreeUtils_1.printOperator)(node.operator),
|
489
|
+
}), node.leftExpression);
|
490
|
+
}
|
491
|
+
else {
|
492
|
+
// If neither the LHS or RHS are unions, don't include a diagnostic addendum
|
493
|
+
// because it will be redundant with the main diagnostic message. The addenda
|
494
|
+
// are useful only if union expansion was used for one or both operands.
|
495
|
+
let diagString = '';
|
496
|
+
if ((0, types_1.isUnion)(evaluator.makeTopLevelTypeVarsConcrete(leftType)) ||
|
497
|
+
(0, types_1.isUnion)(evaluator.makeTopLevelTypeVarsConcrete(rightType))) {
|
498
|
+
diagString = diag.getString();
|
499
|
+
}
|
500
|
+
evaluator.addDiagnostic(fileInfo.diagnosticRuleSet.reportGeneralTypeIssues, diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, localize_1.Localizer.Diagnostic.typeNotSupportBinaryOperator().format({
|
501
|
+
operator: (0, parseTreeUtils_1.printOperator)(node.operator),
|
502
|
+
leftType: evaluator.printType(leftType),
|
503
|
+
rightType: evaluator.printType(rightType),
|
504
|
+
}) + diagString, node);
|
505
|
+
}
|
506
|
+
}
|
507
|
+
type = types_1.UnknownType.create();
|
508
|
+
}
|
509
|
+
return { type, isIncomplete, typeErrors };
|
510
|
+
}
|
511
|
+
exports.getTypeOfBinaryOperation = getTypeOfBinaryOperation;
|
512
|
+
function getTypeOfAugmentedAssignment(evaluator, node, inferenceContext) {
|
513
|
+
const operatorMap = {
|
514
|
+
[1 /* AddEqual */]: ['__iadd__', 0 /* Add */],
|
515
|
+
[34 /* SubtractEqual */]: ['__isub__', 33 /* Subtract */],
|
516
|
+
[27 /* MultiplyEqual */]: ['__imul__', 26 /* Multiply */],
|
517
|
+
[14 /* FloorDivideEqual */]: ['__ifloordiv__', 13 /* FloorDivide */],
|
518
|
+
[11 /* DivideEqual */]: ['__itruediv__', 10 /* Divide */],
|
519
|
+
[25 /* ModEqual */]: ['__imod__', 24 /* Mod */],
|
520
|
+
[30 /* PowerEqual */]: ['__ipow__', 29 /* Power */],
|
521
|
+
[23 /* MatrixMultiplyEqual */]: ['__imatmul__', 22 /* MatrixMultiply */],
|
522
|
+
[4 /* BitwiseAndEqual */]: ['__iand__', 3 /* BitwiseAnd */],
|
523
|
+
[7 /* BitwiseOrEqual */]: ['__ior__', 6 /* BitwiseOr */],
|
524
|
+
[9 /* BitwiseXorEqual */]: ['__ixor__', 8 /* BitwiseXor */],
|
525
|
+
[18 /* LeftShiftEqual */]: ['__ilshift__', 17 /* LeftShift */],
|
526
|
+
[32 /* RightShiftEqual */]: ['__irshift__', 31 /* RightShift */],
|
527
|
+
};
|
528
|
+
let type;
|
529
|
+
let typeResult;
|
530
|
+
const diag = new diagnostic_1.DiagnosticAddendum();
|
531
|
+
const leftTypeResult = evaluator.getTypeOfExpression(node.leftExpression);
|
532
|
+
const leftType = leftTypeResult.type;
|
533
|
+
let expectedOperandType;
|
534
|
+
if (node.operator === 7 /* BitwiseOrEqual */) {
|
535
|
+
// If this is a bitwise or ("|="), use the type of the left operand. This allows
|
536
|
+
// us to support the case where a TypedDict is being updated with a dict expression.
|
537
|
+
expectedOperandType = leftType;
|
538
|
+
}
|
539
|
+
const rightTypeResult = evaluator.getTypeOfExpression(node.rightExpression,
|
540
|
+
/* flags */ undefined, (0, typeUtils_1.makeInferenceContext)(expectedOperandType));
|
541
|
+
const rightType = rightTypeResult.type;
|
542
|
+
const isIncomplete = !!rightTypeResult.isIncomplete || !!leftTypeResult.isIncomplete;
|
543
|
+
if ((0, types_1.isNever)(leftType) || (0, types_1.isNever)(rightType)) {
|
544
|
+
typeResult = { type: types_1.NeverType.createNever(), isIncomplete };
|
545
|
+
}
|
546
|
+
else {
|
547
|
+
type = evaluator.mapSubtypesExpandTypeVars(leftType,
|
548
|
+
/* conditionFilter */ undefined, (leftSubtypeExpanded, leftSubtypeUnexpanded) => {
|
549
|
+
return evaluator.mapSubtypesExpandTypeVars(rightType, (0, typeUtils_1.getTypeCondition)(leftSubtypeExpanded), (rightSubtypeExpanded, rightSubtypeUnexpanded) => {
|
550
|
+
if ((0, types_1.isAnyOrUnknown)(leftSubtypeUnexpanded) || (0, types_1.isAnyOrUnknown)(rightSubtypeUnexpanded)) {
|
551
|
+
return (0, typeUtils_1.preserveUnknown)(leftSubtypeUnexpanded, rightSubtypeUnexpanded);
|
552
|
+
}
|
553
|
+
const magicMethodName = operatorMap[node.operator][0];
|
554
|
+
let returnType = evaluator.getTypeOfMagicMethodReturn(leftSubtypeUnexpanded, [{ type: rightSubtypeUnexpanded, isIncomplete: rightTypeResult.isIncomplete }], magicMethodName, node, inferenceContext);
|
555
|
+
if (!returnType && leftSubtypeUnexpanded !== leftSubtypeExpanded) {
|
556
|
+
// Try with the expanded left type.
|
557
|
+
returnType = evaluator.getTypeOfMagicMethodReturn(leftSubtypeExpanded, [{ type: rightSubtypeUnexpanded, isIncomplete: rightTypeResult.isIncomplete }], magicMethodName, node, inferenceContext);
|
558
|
+
}
|
559
|
+
if (!returnType && rightSubtypeUnexpanded !== rightSubtypeExpanded) {
|
560
|
+
// Try with the expanded left and right type.
|
561
|
+
returnType = evaluator.getTypeOfMagicMethodReturn(leftSubtypeExpanded, [{ type: rightSubtypeExpanded, isIncomplete: rightTypeResult.isIncomplete }], magicMethodName, node, inferenceContext);
|
562
|
+
}
|
563
|
+
if (!returnType) {
|
564
|
+
// If the LHS class didn't support the magic method for augmented
|
565
|
+
// assignment, fall back on the normal binary expression evaluator.
|
566
|
+
const binaryOperator = operatorMap[node.operator][1];
|
567
|
+
// Don't use literal math if either of the operation is within a loop
|
568
|
+
// because the literal values may change each time.
|
569
|
+
const isLiteralMathAllowed = !(0, parseTreeUtils_1.isWithinLoop)(node) &&
|
570
|
+
(0, typeUtils_1.getUnionSubtypeCount)(leftType) * (0, typeUtils_1.getUnionSubtypeCount)(rightType) <
|
571
|
+
maxLiteralMathSubtypeCount;
|
572
|
+
// Don't special-case tuple __add__ if the left type is a union. This
|
573
|
+
// can result in an infinite loop if we keep creating new tuple types
|
574
|
+
// within a loop construct using __add__.
|
575
|
+
const isTupleAddAllowed = !(0, types_1.isUnion)(leftType);
|
576
|
+
returnType = validateBinaryOperation(evaluator, binaryOperator, { type: leftSubtypeUnexpanded, isIncomplete: leftTypeResult.isIncomplete }, { type: rightSubtypeUnexpanded, isIncomplete: rightTypeResult.isIncomplete }, node, inferenceContext, diag, { isLiteralMathAllowed, isTupleAddAllowed });
|
577
|
+
}
|
578
|
+
return returnType;
|
579
|
+
});
|
580
|
+
});
|
581
|
+
// If the LHS class didn't support the magic method for augmented
|
582
|
+
// assignment, fall back on the normal binary expression evaluator.
|
583
|
+
if (!diag.isEmpty() || !type || (0, types_1.isNever)(type)) {
|
584
|
+
if (!isIncomplete) {
|
585
|
+
const fileInfo = (0, analyzerNodeInfo_1.getFileInfo)(node);
|
586
|
+
evaluator.addDiagnostic(fileInfo.diagnosticRuleSet.reportGeneralTypeIssues, diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, localize_1.Localizer.Diagnostic.typeNotSupportBinaryOperator().format({
|
587
|
+
operator: (0, parseTreeUtils_1.printOperator)(node.operator),
|
588
|
+
leftType: evaluator.printType(leftType),
|
589
|
+
rightType: evaluator.printType(rightType),
|
590
|
+
}) + diag.getString(), node);
|
591
|
+
}
|
592
|
+
type = types_1.UnknownType.create();
|
593
|
+
}
|
594
|
+
typeResult = { type, isIncomplete };
|
595
|
+
}
|
596
|
+
evaluator.assignTypeToExpression(node.destExpression, typeResult.type, !!typeResult.isIncomplete, node.rightExpression);
|
597
|
+
return typeResult;
|
598
|
+
}
|
599
|
+
exports.getTypeOfAugmentedAssignment = getTypeOfAugmentedAssignment;
|
600
|
+
function getTypeOfUnaryOperation(evaluator, node, inferenceContext) {
|
601
|
+
const exprTypeResult = evaluator.getTypeOfExpression(node.expression);
|
602
|
+
let exprType = evaluator.makeTopLevelTypeVarsConcrete(exprTypeResult.type);
|
603
|
+
const isIncomplete = exprTypeResult.isIncomplete;
|
604
|
+
if ((0, types_1.isNever)(exprType)) {
|
605
|
+
return { type: types_1.NeverType.createNever(), isIncomplete };
|
606
|
+
}
|
607
|
+
// Map unary operators to magic functions. Note that the bitwise
|
608
|
+
// invert has two magic functions that are aliases of each other.
|
609
|
+
const unaryOperatorMap = {
|
610
|
+
[0 /* Add */]: '__pos__',
|
611
|
+
[33 /* Subtract */]: '__neg__',
|
612
|
+
[5 /* BitwiseInvert */]: '__invert__',
|
613
|
+
};
|
614
|
+
let type;
|
615
|
+
if (node.operator !== 38 /* Not */) {
|
616
|
+
if ((0, typeUtils_1.isOptionalType)(exprType)) {
|
617
|
+
evaluator.addDiagnostic((0, analyzerNodeInfo_1.getFileInfo)(node).diagnosticRuleSet.reportOptionalOperand, diagnosticRules_1.DiagnosticRule.reportOptionalOperand, localize_1.Localizer.Diagnostic.noneOperator().format({
|
618
|
+
operator: (0, parseTreeUtils_1.printOperator)(node.operator),
|
619
|
+
}), node.expression);
|
620
|
+
exprType = (0, types_1.removeNoneFromUnion)(exprType);
|
621
|
+
}
|
622
|
+
}
|
623
|
+
// Handle certain operations on certain literal types
|
624
|
+
// using special-case math. Do not apply this if the input type
|
625
|
+
// is incomplete because we may be evaluating an expression within
|
626
|
+
// a loop, so the literal value may change each time.
|
627
|
+
if (!exprTypeResult.isIncomplete) {
|
628
|
+
const literalClassName = (0, typeUtils_1.getLiteralTypeClassName)(exprType);
|
629
|
+
if (literalClassName === 'int') {
|
630
|
+
if (node.operator === 0 /* Add */) {
|
631
|
+
type = exprType;
|
632
|
+
}
|
633
|
+
else if (node.operator === 33 /* Subtract */) {
|
634
|
+
type = (0, typeUtils_1.mapSubtypes)(exprType, (subtype) => {
|
635
|
+
const classSubtype = subtype;
|
636
|
+
return types_1.ClassType.cloneWithLiteral(classSubtype, -classSubtype.literalValue);
|
637
|
+
});
|
638
|
+
}
|
639
|
+
}
|
640
|
+
else if (literalClassName === 'bool') {
|
641
|
+
if (node.operator === 38 /* Not */) {
|
642
|
+
type = (0, typeUtils_1.mapSubtypes)(exprType, (subtype) => {
|
643
|
+
const classSubtype = subtype;
|
644
|
+
return types_1.ClassType.cloneWithLiteral(classSubtype, !classSubtype.literalValue);
|
645
|
+
});
|
646
|
+
}
|
647
|
+
}
|
648
|
+
}
|
649
|
+
if (!type) {
|
650
|
+
// __not__ always returns a boolean.
|
651
|
+
if (node.operator === 38 /* Not */) {
|
652
|
+
type = evaluator.getBuiltInObject(node, 'bool');
|
653
|
+
if (!type) {
|
654
|
+
type = types_1.UnknownType.create();
|
655
|
+
}
|
656
|
+
}
|
657
|
+
else {
|
658
|
+
if ((0, types_1.isAnyOrUnknown)(exprType)) {
|
659
|
+
type = exprType;
|
660
|
+
}
|
661
|
+
else {
|
662
|
+
const magicMethodName = unaryOperatorMap[node.operator];
|
663
|
+
type = evaluator.getTypeOfMagicMethodReturn(exprType, [], magicMethodName, node, inferenceContext);
|
664
|
+
}
|
665
|
+
if (!type) {
|
666
|
+
const fileInfo = (0, analyzerNodeInfo_1.getFileInfo)(node);
|
667
|
+
if (inferenceContext) {
|
668
|
+
evaluator.addDiagnostic(fileInfo.diagnosticRuleSet.reportGeneralTypeIssues, diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, localize_1.Localizer.Diagnostic.typeNotSupportUnaryOperatorBidirectional().format({
|
669
|
+
operator: (0, parseTreeUtils_1.printOperator)(node.operator),
|
670
|
+
type: evaluator.printType(exprType),
|
671
|
+
expectedType: evaluator.printType(inferenceContext.expectedType),
|
672
|
+
}), node);
|
673
|
+
}
|
674
|
+
else {
|
675
|
+
evaluator.addDiagnostic(fileInfo.diagnosticRuleSet.reportGeneralTypeIssues, diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, localize_1.Localizer.Diagnostic.typeNotSupportUnaryOperator().format({
|
676
|
+
operator: (0, parseTreeUtils_1.printOperator)(node.operator),
|
677
|
+
type: evaluator.printType(exprType),
|
678
|
+
}), node);
|
679
|
+
}
|
680
|
+
type = types_1.UnknownType.create();
|
681
|
+
}
|
682
|
+
}
|
683
|
+
}
|
684
|
+
return { type, isIncomplete };
|
685
|
+
}
|
686
|
+
exports.getTypeOfUnaryOperation = getTypeOfUnaryOperation;
|
687
|
+
function getTypeOfTernaryOperation(evaluator, node, flags, inferenceContext) {
|
688
|
+
evaluator.getTypeOfExpression(node.testExpression);
|
689
|
+
const typesToCombine = [];
|
690
|
+
let isIncomplete = false;
|
691
|
+
let typeErrors = false;
|
692
|
+
const fileInfo = (0, analyzerNodeInfo_1.getFileInfo)(node);
|
693
|
+
const constExprValue = (0, staticExpressions_1.evaluateStaticBoolExpression)(node.testExpression, fileInfo.executionEnvironment, fileInfo.definedConstants);
|
694
|
+
if (constExprValue !== false && evaluator.isNodeReachable(node.ifExpression)) {
|
695
|
+
const ifType = evaluator.getTypeOfExpression(node.ifExpression, flags, inferenceContext);
|
696
|
+
typesToCombine.push(ifType.type);
|
697
|
+
if (ifType.isIncomplete) {
|
698
|
+
isIncomplete = true;
|
699
|
+
}
|
700
|
+
if (ifType.typeErrors) {
|
701
|
+
typeErrors = true;
|
702
|
+
}
|
703
|
+
}
|
704
|
+
if (constExprValue !== true && evaluator.isNodeReachable(node.elseExpression)) {
|
705
|
+
const elseType = evaluator.getTypeOfExpression(node.elseExpression, flags, inferenceContext);
|
706
|
+
typesToCombine.push(elseType.type);
|
707
|
+
if (elseType.isIncomplete) {
|
708
|
+
isIncomplete = true;
|
709
|
+
}
|
710
|
+
if (elseType.typeErrors) {
|
711
|
+
typeErrors = true;
|
712
|
+
}
|
713
|
+
}
|
714
|
+
return { type: (0, types_1.combineTypes)(typesToCombine), isIncomplete, typeErrors };
|
715
|
+
}
|
716
|
+
exports.getTypeOfTernaryOperation = getTypeOfTernaryOperation;
|
717
|
+
function customMetaclassSupportsMethod(type, methodName) {
|
718
|
+
if (!(0, types_1.isInstantiableClass)(type)) {
|
719
|
+
return false;
|
720
|
+
}
|
721
|
+
const metaclass = type.details.effectiveMetaclass;
|
722
|
+
if (!metaclass || !(0, types_1.isInstantiableClass)(metaclass)) {
|
723
|
+
return false;
|
724
|
+
}
|
725
|
+
if (types_1.ClassType.isBuiltIn(metaclass, 'type')) {
|
726
|
+
return false;
|
727
|
+
}
|
728
|
+
const memberInfo = (0, typeUtils_1.lookUpClassMember)(metaclass, methodName);
|
729
|
+
if (!memberInfo) {
|
730
|
+
return false;
|
731
|
+
}
|
732
|
+
if ((0, types_1.isInstantiableClass)(memberInfo.classType) && types_1.ClassType.isBuiltIn(memberInfo.classType, 'type')) {
|
733
|
+
return false;
|
734
|
+
}
|
735
|
+
return true;
|
736
|
+
}
|
737
|
+
// All functions in Python derive from object, so they inherit all
|
738
|
+
// of the capabilities of an object. This function converts a function
|
739
|
+
// to an object instance.
|
740
|
+
function convertFunctionToObject(evaluator, type) {
|
741
|
+
if ((0, types_1.isFunction)(type) || (0, types_1.isOverloadedFunction)(type)) {
|
742
|
+
const objectType = evaluator.getObjectType();
|
743
|
+
if (objectType) {
|
744
|
+
return objectType;
|
745
|
+
}
|
746
|
+
}
|
747
|
+
return type;
|
748
|
+
}
|
749
|
+
//# sourceMappingURL=operations.js.map
|