@zzzen/pyright-internal 1.2.0-dev.20231224 → 1.2.0-dev.20240107
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 +13 -6
- package/dist/analyzer/binder.js.map +1 -1
- package/dist/analyzer/checker.d.ts +3 -0
- package/dist/analyzer/checker.js +167 -42
- package/dist/analyzer/checker.js.map +1 -1
- package/dist/analyzer/codeFlowEngine.js +7 -4
- package/dist/analyzer/codeFlowEngine.js.map +1 -1
- package/dist/analyzer/constraintSolver.js +21 -17
- package/dist/analyzer/constraintSolver.js.map +1 -1
- package/dist/analyzer/dataClasses.js +2 -9
- package/dist/analyzer/dataClasses.js.map +1 -1
- package/dist/analyzer/enums.js +1 -1
- package/dist/analyzer/enums.js.map +1 -1
- package/dist/analyzer/namedTuples.js +14 -6
- package/dist/analyzer/namedTuples.js.map +1 -1
- package/dist/analyzer/protocols.d.ts +2 -0
- package/dist/analyzer/protocols.js +75 -6
- package/dist/analyzer/protocols.js.map +1 -1
- package/dist/analyzer/scopeUtils.d.ts +1 -0
- package/dist/analyzer/scopeUtils.js +12 -1
- package/dist/analyzer/scopeUtils.js.map +1 -1
- package/dist/analyzer/typeEvaluator.js +339 -219
- package/dist/analyzer/typeEvaluator.js.map +1 -1
- package/dist/analyzer/typeEvaluatorTypes.d.ts +2 -1
- package/dist/analyzer/typeEvaluatorTypes.js +2 -0
- package/dist/analyzer/typeEvaluatorTypes.js.map +1 -1
- package/dist/analyzer/typeGuards.js +10 -6
- package/dist/analyzer/typeGuards.js.map +1 -1
- package/dist/analyzer/typePrinter.js +4 -2
- package/dist/analyzer/typePrinter.js.map +1 -1
- package/dist/analyzer/typeUtils.d.ts +10 -9
- package/dist/analyzer/typeUtils.js +20 -14
- package/dist/analyzer/typeUtils.js.map +1 -1
- package/dist/analyzer/typedDicts.js +24 -36
- package/dist/analyzer/typedDicts.js.map +1 -1
- package/dist/analyzer/types.d.ts +8 -2
- package/dist/analyzer/types.js +58 -8
- package/dist/analyzer/types.js.map +1 -1
- package/dist/backgroundAnalysisBase.js +4 -3
- package/dist/backgroundAnalysisBase.js.map +1 -1
- package/dist/backgroundThreadBase.d.ts +1 -0
- package/dist/backgroundThreadBase.js +8 -1
- package/dist/backgroundThreadBase.js.map +1 -1
- package/dist/common/diagnostic.d.ts +1 -0
- package/dist/common/diagnostic.js +18 -1
- package/dist/common/diagnostic.js.map +1 -1
- package/dist/common/realFileSystem.js +44 -12
- package/dist/common/realFileSystem.js.map +1 -1
- package/dist/localization/localize.d.ts +45 -0
- package/dist/localization/localize.js +22 -0
- package/dist/localization/localize.js.map +1 -1
- package/dist/localization/package.nls.en-us.json +24 -2
- package/dist/parser/parser.js +1 -1
- package/dist/parser/parser.js.map +1 -1
- package/dist/pyright.js +6 -3
- package/dist/pyright.js.map +1 -1
- package/dist/tests/localizer.test.js +1 -1
- package/dist/tests/localizer.test.js.map +1 -1
- package/dist/tests/typeEvaluator1.test.js +2 -2
- package/dist/tests/typeEvaluator2.test.js +22 -10
- package/dist/tests/typeEvaluator2.test.js.map +1 -1
- package/dist/tests/typeEvaluator3.test.js +3 -3
- package/dist/tests/typeEvaluator3.test.js.map +1 -1
- package/dist/tests/typeEvaluator4.test.js +7 -3
- package/dist/tests/typeEvaluator4.test.js.map +1 -1
- package/dist/tests/typeEvaluator5.test.js +1 -1
- package/dist/tests/typePrinter.test.js +2 -10
- package/dist/tests/typePrinter.test.js.map +1 -1
- package/dist/tests/uri.test.js +7 -0
- package/dist/tests/uri.test.js.map +1 -1
- package/package.json +1 -1
package/dist/analyzer/checker.js
CHANGED
@@ -60,6 +60,7 @@ const parameterUtils_1 = require("./parameterUtils");
|
|
60
60
|
const ParseTreeUtils = __importStar(require("./parseTreeUtils"));
|
61
61
|
const parseTreeWalker_1 = require("./parseTreeWalker");
|
62
62
|
const patternMatching_1 = require("./patternMatching");
|
63
|
+
const protocols_1 = require("./protocols");
|
63
64
|
const regions_1 = require("./regions");
|
64
65
|
const scopeUtils_1 = require("./scopeUtils");
|
65
66
|
const sourceFile_1 = require("./sourceFile");
|
@@ -162,8 +163,8 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
162
163
|
!types_1.ClassType.isBuiltIn(baseClassType, 'Generic')) {
|
163
164
|
if (!types_1.ClassType.isProtocolClass(baseClassType)) {
|
164
165
|
this._evaluator.addError(localize_1.Localizer.Diagnostic.protocolBaseClass().format({
|
165
|
-
classType:
|
166
|
-
baseType:
|
166
|
+
classType: classTypeResult.classType.details.name,
|
167
|
+
baseType: baseClassType.details.name,
|
167
168
|
}), arg.valueExpression);
|
168
169
|
}
|
169
170
|
}
|
@@ -179,6 +180,7 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
179
180
|
this._validateSlotsClassVarConflict(classTypeResult.classType);
|
180
181
|
}
|
181
182
|
this._validateBaseClassOverrides(classTypeResult.classType);
|
183
|
+
this._validateOverloadDecoratorConsistency(classTypeResult.classType);
|
182
184
|
this._validateMultipleInheritanceBaseClasses(classTypeResult.classType, node.name);
|
183
185
|
this._validateMultipleInheritanceCompatibility(classTypeResult.classType, node.name);
|
184
186
|
this._validateConstructorConsistency(classTypeResult.classType, node.name);
|
@@ -386,6 +388,10 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
386
388
|
this._validateFunctionTypeVarUsage(node, functionTypeResult);
|
387
389
|
this._validateGeneratorReturnType(node, functionTypeResult.functionType);
|
388
390
|
this._reportDeprecatedClassProperty(node, functionTypeResult);
|
391
|
+
// If this is not a method, @final is disallowed.
|
392
|
+
if (!containingClassNode && types_1.FunctionType.isFinal(functionTypeResult.functionType)) {
|
393
|
+
this._evaluator.addDiagnostic(this._fileInfo.diagnosticRuleSet.reportGeneralTypeIssues, diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, localize_1.Localizer.Diagnostic.finalNonMethod().format({ name: node.name.value }), node.name);
|
394
|
+
}
|
389
395
|
}
|
390
396
|
// If we're at the module level within a stub file, report a diagnostic
|
391
397
|
// if there is a '__getattr__' function defined when in strict mode.
|
@@ -564,7 +570,7 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
564
570
|
let diagAddendum = new diagnostic_1.DiagnosticAddendum();
|
565
571
|
let returnTypeMatches = false;
|
566
572
|
if (this._evaluator.assignType(declaredReturnType, returnTypeResult.type, diagAddendum, new typeVarContext_1.TypeVarContext(),
|
567
|
-
/* srcTypeVarContext */ undefined,
|
573
|
+
/* srcTypeVarContext */ undefined, 128 /* AssignTypeFlags.AllowBoolTypeGuard */)) {
|
568
574
|
returnTypeMatches = true;
|
569
575
|
}
|
570
576
|
else {
|
@@ -587,7 +593,7 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
587
593
|
const adjustedReturnType = (0, typeUtils_1.applySolvedTypeVars)(declaredReturnType, typeVarContext);
|
588
594
|
if (this._evaluator.assignType(adjustedReturnType, returnTypeResult.type, diagAddendum,
|
589
595
|
/* destTypeVarContext */ undefined,
|
590
|
-
/* srcTypeVarContext */ undefined,
|
596
|
+
/* srcTypeVarContext */ undefined, 128 /* AssignTypeFlags.AllowBoolTypeGuard */)) {
|
591
597
|
returnTypeMatches = true;
|
592
598
|
}
|
593
599
|
}
|
@@ -1731,7 +1737,7 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
1731
1737
|
_validateOverloadConsistency(node, functionType, prevOverloads) {
|
1732
1738
|
for (let i = 0; i < prevOverloads.length; i++) {
|
1733
1739
|
const prevOverload = prevOverloads[i];
|
1734
|
-
if (this._isOverlappingOverload(functionType, prevOverload)) {
|
1740
|
+
if (this._isOverlappingOverload(functionType, prevOverload, /* partialOverlap */ false)) {
|
1735
1741
|
this._evaluator.addDiagnostic(this._fileInfo.diagnosticRuleSet.reportOverlappingOverload, diagnosticRules_1.DiagnosticRule.reportOverlappingOverload, localize_1.Localizer.Diagnostic.overlappingOverload().format({
|
1736
1742
|
name: node.name.value,
|
1737
1743
|
obscured: prevOverloads.length + 1,
|
@@ -1742,14 +1748,14 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
1742
1748
|
}
|
1743
1749
|
for (let i = 0; i < prevOverloads.length; i++) {
|
1744
1750
|
const prevOverload = prevOverloads[i];
|
1745
|
-
if (this._isOverlappingOverload(prevOverload, functionType)) {
|
1751
|
+
if (this._isOverlappingOverload(prevOverload, functionType, /* partialOverlap */ true)) {
|
1746
1752
|
const prevReturnType = types_1.FunctionType.getSpecializedReturnType(prevOverload);
|
1747
1753
|
const returnType = types_1.FunctionType.getSpecializedReturnType(functionType);
|
1748
1754
|
if (prevReturnType &&
|
1749
1755
|
returnType &&
|
1750
1756
|
!this._evaluator.assignType(returnType, prevReturnType,
|
1751
1757
|
/* diag */ undefined, new typeVarContext_1.TypeVarContext(),
|
1752
|
-
/* srcTypeVarContext */ undefined, 8 /* AssignTypeFlags.SkipSolveTypeVars */ |
|
1758
|
+
/* srcTypeVarContext */ undefined, 8 /* AssignTypeFlags.SkipSolveTypeVars */ | 1024 /* AssignTypeFlags.IgnoreTypeVarScope */)) {
|
1753
1759
|
const altNode = this._findNodeForOverload(node, prevOverload);
|
1754
1760
|
this._evaluator.addDiagnostic(this._fileInfo.diagnosticRuleSet.reportOverlappingOverload, diagnosticRules_1.DiagnosticRule.reportOverlappingOverload, localize_1.Localizer.Diagnostic.overloadReturnTypeMismatch().format({
|
1755
1761
|
name: node.name.value,
|
@@ -1779,7 +1785,7 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
1779
1785
|
}
|
1780
1786
|
return undefined;
|
1781
1787
|
}
|
1782
|
-
_isOverlappingOverload(functionType, prevOverload) {
|
1788
|
+
_isOverlappingOverload(functionType, prevOverload, partialOverlap) {
|
1783
1789
|
// According to precedent, the __get__ method is special-cased and is
|
1784
1790
|
// exempt from overlapping overload checks. It's not clear why this is
|
1785
1791
|
// the case, but for consistency with other type checkers, we'll honor
|
@@ -1788,18 +1794,22 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
1788
1794
|
if (types_1.FunctionType.isInstanceMethod(functionType) && functionType.details.name === '__get__') {
|
1789
1795
|
return false;
|
1790
1796
|
}
|
1797
|
+
let flags = 64 /* AssignTypeFlags.SkipFunctionReturnTypeCheck */ | 16 /* AssignTypeFlags.OverloadOverlapCheck */;
|
1798
|
+
if (partialOverlap) {
|
1799
|
+
flags |= 32 /* AssignTypeFlags.PartialOverloadOverlapCheck */;
|
1800
|
+
}
|
1791
1801
|
return this._evaluator.assignType(functionType, prevOverload,
|
1792
1802
|
/* diag */ undefined, new typeVarContext_1.TypeVarContext((0, typeUtils_1.getTypeVarScopeId)(functionType)),
|
1793
|
-
/* srcTypeVarContext */ undefined,
|
1803
|
+
/* srcTypeVarContext */ undefined, flags);
|
1794
1804
|
}
|
1795
1805
|
_isLegalOverloadImplementation(overload, implementation, diag) {
|
1796
1806
|
var _a;
|
1797
1807
|
const implTypeVarContext = new typeVarContext_1.TypeVarContext((0, typeUtils_1.getTypeVarScopeId)(implementation));
|
1798
1808
|
const overloadTypeVarContext = new typeVarContext_1.TypeVarContext((0, typeUtils_1.getTypeVarScopeId)(overload));
|
1799
1809
|
// First check the parameters to see if they are assignable.
|
1800
|
-
let isLegal = this._evaluator.assignType(overload, implementation, diag, overloadTypeVarContext, implTypeVarContext,
|
1810
|
+
let isLegal = this._evaluator.assignType(overload, implementation, diag, overloadTypeVarContext, implTypeVarContext, 64 /* AssignTypeFlags.SkipFunctionReturnTypeCheck */ |
|
1801
1811
|
2 /* AssignTypeFlags.ReverseTypeVarMatching */ |
|
1802
|
-
|
1812
|
+
512 /* AssignTypeFlags.SkipSelfClsTypeCheck */);
|
1803
1813
|
// Now check the return types.
|
1804
1814
|
const overloadReturnType = (_a = overload.details.declaredReturnType) !== null && _a !== void 0 ? _a : this._evaluator.getFunctionInferredReturnType(overload);
|
1805
1815
|
const implementationReturnType = (0, typeUtils_1.applySolvedTypeVars)(implementation.details.declaredReturnType || this._evaluator.getFunctionInferredReturnType(implementation), implTypeVarContext);
|
@@ -2538,6 +2548,23 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
2538
2548
|
type: this._evaluator.printType(arg1Type),
|
2539
2549
|
}) + diag.getString(), node.arguments[1]);
|
2540
2550
|
}
|
2551
|
+
// If this call is an issubclass, check for the use of a "data protocol",
|
2552
|
+
// which PEP 544 says cannot be used in issubclass.
|
2553
|
+
if (!isInstanceCheck) {
|
2554
|
+
const diag = new diagnostic_1.DiagnosticAddendum();
|
2555
|
+
(0, typeUtils_1.doForEachSubtype)(arg1Type, (arg1Subtype) => {
|
2556
|
+
if ((0, types_1.isInstantiableClass)(arg1Subtype) &&
|
2557
|
+
types_1.ClassType.isProtocolClass(arg1Subtype) &&
|
2558
|
+
!(0, protocols_1.isMethodOnlyProtocol)(arg1Subtype)) {
|
2559
|
+
diag.addMessage(localize_1.Localizer.DiagnosticAddendum.dataProtocolUnsupported().format({
|
2560
|
+
name: arg1Subtype.details.name,
|
2561
|
+
}));
|
2562
|
+
}
|
2563
|
+
});
|
2564
|
+
if (!diag.isEmpty()) {
|
2565
|
+
this._evaluator.addDiagnostic(this._fileInfo.diagnosticRuleSet.reportGeneralTypeIssues, diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, localize_1.Localizer.Diagnostic.dataProtocolInSubclassCheck(), node.arguments[1]);
|
2566
|
+
}
|
2567
|
+
}
|
2541
2568
|
// If this call is within an assert statement, we won't check whether
|
2542
2569
|
// it's unnecessary.
|
2543
2570
|
let curNode = node;
|
@@ -2573,6 +2600,9 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
2573
2600
|
arg1IncludesSubclasses = true;
|
2574
2601
|
}
|
2575
2602
|
}
|
2603
|
+
if (arg0Type) {
|
2604
|
+
this._validateUnsafeProtocolOverlap(node.arguments[0].valueExpression, (0, typeUtils_1.convertToInstance)(arg1Subtype), isInstanceCheck ? arg0Type : (0, typeUtils_1.convertToInstance)(arg0Type));
|
2605
|
+
}
|
2576
2606
|
}
|
2577
2607
|
else {
|
2578
2608
|
// The isinstance and issubclass call supports a variation where the second
|
@@ -2585,6 +2615,9 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
2585
2615
|
if (typeArg.type.includeSubclasses) {
|
2586
2616
|
arg1IncludesSubclasses = true;
|
2587
2617
|
}
|
2618
|
+
if (arg0Type) {
|
2619
|
+
this._validateUnsafeProtocolOverlap(node.arguments[0].valueExpression, (0, typeUtils_1.convertToInstance)(typeArg.type), isInstanceCheck ? arg0Type : (0, typeUtils_1.convertToInstance)(arg0Type));
|
2620
|
+
}
|
2588
2621
|
}
|
2589
2622
|
else {
|
2590
2623
|
isValidType = false;
|
@@ -2698,6 +2731,29 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
2698
2731
|
}), node);
|
2699
2732
|
}
|
2700
2733
|
}
|
2734
|
+
_validateUnsafeProtocolOverlap(errorNode, protocol, testType) {
|
2735
|
+
// If this is a protocol class, check for an "unsafe overlap"
|
2736
|
+
// with the arg0 type.
|
2737
|
+
if (types_1.ClassType.isProtocolClass(protocol)) {
|
2738
|
+
let isUnsafeOverlap = false;
|
2739
|
+
const diag = new diagnostic_1.DiagnosticAddendum();
|
2740
|
+
(0, typeUtils_1.doForEachSubtype)(testType, (testSubtype) => {
|
2741
|
+
if ((0, types_1.isClassInstance)(testSubtype)) {
|
2742
|
+
if ((0, protocols_1.isProtocolUnsafeOverlap)(this._evaluator, protocol, testSubtype)) {
|
2743
|
+
isUnsafeOverlap = true;
|
2744
|
+
diag.addMessage(localize_1.Localizer.DiagnosticAddendum.protocolUnsafeOverlap().format({
|
2745
|
+
name: testSubtype.details.name,
|
2746
|
+
}));
|
2747
|
+
}
|
2748
|
+
}
|
2749
|
+
});
|
2750
|
+
if (isUnsafeOverlap) {
|
2751
|
+
this._evaluator.addDiagnostic(this._fileInfo.diagnosticRuleSet.reportGeneralTypeIssues, diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, localize_1.Localizer.Diagnostic.protocolUnsafeOverlap().format({
|
2752
|
+
name: protocol.details.name,
|
2753
|
+
}) + diag.getString(), errorNode);
|
2754
|
+
}
|
2755
|
+
}
|
2756
|
+
}
|
2701
2757
|
// Determines whether the specified type is allowed as the second argument
|
2702
2758
|
// to an isinstance or issubclass check.
|
2703
2759
|
_isTypeSupportedTypeForIsInstance(type, isInstanceCheck, diag) {
|
@@ -2715,6 +2771,10 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
2715
2771
|
diag.addMessage(localize_1.Localizer.DiagnosticAddendum.noneNotAllowed());
|
2716
2772
|
isSupported = false;
|
2717
2773
|
}
|
2774
|
+
else if (types_1.ClassType.isTypedDictClass(subtype)) {
|
2775
|
+
diag.addMessage(localize_1.Localizer.DiagnosticAddendum.typedDictClassNotAllowed());
|
2776
|
+
isSupported = false;
|
2777
|
+
}
|
2718
2778
|
else if (subtype.isTypeArgumentExplicit && !subtype.includeSubclasses) {
|
2719
2779
|
// If it's a class, make sure that it has not been given explicit
|
2720
2780
|
// type arguments. This will result in a TypeError exception.
|
@@ -2730,6 +2790,10 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
2730
2790
|
diag.addMessage(localize_1.Localizer.DiagnosticAddendum.protocolRequiresRuntimeCheckable());
|
2731
2791
|
isSupported = false;
|
2732
2792
|
}
|
2793
|
+
else if (types_1.ClassType.isNewTypeClass(subtype)) {
|
2794
|
+
diag.addMessage(localize_1.Localizer.DiagnosticAddendum.newTypeClassNotAllowed());
|
2795
|
+
isSupported = false;
|
2796
|
+
}
|
2733
2797
|
break;
|
2734
2798
|
case 4 /* TypeCategory.Function */:
|
2735
2799
|
if (!types_1.TypeBase.isInstantiable(subtype) || subtype.isCallableWithTypeArgs) {
|
@@ -3782,11 +3846,11 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
3782
3846
|
if (!this._evaluator.assignType(newMemberType, initMemberType,
|
3783
3847
|
/* diag */ undefined,
|
3784
3848
|
/* destTypeVarContext */ undefined,
|
3785
|
-
/* srcTypeVarContext */ undefined,
|
3849
|
+
/* srcTypeVarContext */ undefined, 64 /* AssignTypeFlags.SkipFunctionReturnTypeCheck */) ||
|
3786
3850
|
!this._evaluator.assignType(initMemberType, newMemberType,
|
3787
3851
|
/* diag */ undefined,
|
3788
3852
|
/* destTypeVarContext */ undefined,
|
3789
|
-
/* srcTypeVarContext */ undefined,
|
3853
|
+
/* srcTypeVarContext */ undefined, 64 /* AssignTypeFlags.SkipFunctionReturnTypeCheck */)) {
|
3790
3854
|
const displayOnInit = types_1.ClassType.isSameGenericClass(initMethodResult.classType, classType);
|
3791
3855
|
const initDecl = initMemberType.details.declaration;
|
3792
3856
|
const newDecl = newMemberType.details.declaration;
|
@@ -4078,6 +4142,51 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
4078
4142
|
}), overrideDecl.uri, overrideDecl.range);
|
4079
4143
|
}
|
4080
4144
|
}
|
4145
|
+
// Validates that any overloaded methods are consistent in how they
|
4146
|
+
// are decorated. For example, if the first overload is not marked @final
|
4147
|
+
// but subsequent ones are, an error should be reported.
|
4148
|
+
_validateOverloadDecoratorConsistency(classType) {
|
4149
|
+
classType.details.fields.forEach((symbol, name) => {
|
4150
|
+
const primaryDecl = (0, symbolUtils_1.getLastTypedDeclaredForSymbol)(symbol);
|
4151
|
+
if (!primaryDecl || primaryDecl.type !== 5 /* DeclarationType.Function */) {
|
4152
|
+
return;
|
4153
|
+
}
|
4154
|
+
const typeOfSymbol = this._evaluator.getEffectiveTypeOfSymbol(symbol);
|
4155
|
+
if (!(0, types_1.isOverloadedFunction)(typeOfSymbol)) {
|
4156
|
+
return;
|
4157
|
+
}
|
4158
|
+
const overloads = types_1.OverloadedFunctionType.getOverloads(typeOfSymbol);
|
4159
|
+
// If there's an implementation, it will determine whether the
|
4160
|
+
// function is @final.
|
4161
|
+
const implementation = types_1.OverloadedFunctionType.getImplementation(typeOfSymbol);
|
4162
|
+
if (implementation) {
|
4163
|
+
// If one or more of the overloads is marked @final but the
|
4164
|
+
// implementation is not, report an error.
|
4165
|
+
if (!types_1.FunctionType.isFinal(implementation)) {
|
4166
|
+
overloads.forEach((overload) => {
|
4167
|
+
var _a, _b;
|
4168
|
+
if (types_1.FunctionType.isFinal(overload) && ((_a = overload.details.declaration) === null || _a === void 0 ? void 0 : _a.node)) {
|
4169
|
+
this._evaluator.addDiagnostic(this._fileInfo.diagnosticRuleSet.reportGeneralTypeIssues, diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, localize_1.Localizer.Diagnostic.overloadFinalInconsistencyImpl().format({
|
4170
|
+
name: overload.details.name,
|
4171
|
+
}), (_b = (0, declarationUtils_1.getNameNodeForDeclaration)(overload.details.declaration)) !== null && _b !== void 0 ? _b : overload.details.declaration.node);
|
4172
|
+
}
|
4173
|
+
});
|
4174
|
+
}
|
4175
|
+
return;
|
4176
|
+
}
|
4177
|
+
if (!types_1.FunctionType.isFinal(overloads[0])) {
|
4178
|
+
overloads.slice(1).forEach((overload, index) => {
|
4179
|
+
var _a, _b;
|
4180
|
+
if (types_1.FunctionType.isFinal(overload) && ((_a = overload.details.declaration) === null || _a === void 0 ? void 0 : _a.node)) {
|
4181
|
+
this._evaluator.addDiagnostic(this._fileInfo.diagnosticRuleSet.reportGeneralTypeIssues, diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, localize_1.Localizer.Diagnostic.overloadFinalInconsistencyNoImpl().format({
|
4182
|
+
name: overload.details.name,
|
4183
|
+
index: index + 2,
|
4184
|
+
}), (_b = (0, declarationUtils_1.getNameNodeForDeclaration)(overload.details.declaration)) !== null && _b !== void 0 ? _b : overload.details.declaration.node);
|
4185
|
+
}
|
4186
|
+
});
|
4187
|
+
}
|
4188
|
+
});
|
4189
|
+
}
|
4081
4190
|
// Validates that any overridden methods or variables contain the same
|
4082
4191
|
// types as the original method. Also marks the class as abstract if one
|
4083
4192
|
// or more abstract methods are not overridden.
|
@@ -4150,7 +4259,7 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
4150
4259
|
return;
|
4151
4260
|
}
|
4152
4261
|
// Constructors are exempt.
|
4153
|
-
if (
|
4262
|
+
if (this._isMethodExemptFromLsp(overrideFunction.details.name)) {
|
4154
4263
|
return;
|
4155
4264
|
}
|
4156
4265
|
// If the declaration for the override function is not the same as the
|
@@ -4164,6 +4273,11 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
4164
4273
|
className: this._evaluator.printType((0, typeUtils_1.convertToInstance)(baseMember.classType)),
|
4165
4274
|
}), funcNode.name);
|
4166
4275
|
}
|
4276
|
+
// Determines whether the name is exempt from Liskov Substitution Principle rules.
|
4277
|
+
_isMethodExemptFromLsp(name) {
|
4278
|
+
const exemptMethods = ['__init__', '__new__', '__init_subclass__', '__post_init__'];
|
4279
|
+
return exemptMethods.some((n) => n === name);
|
4280
|
+
}
|
4167
4281
|
// Determines whether the type is a function or overloaded function with an @override
|
4168
4282
|
// decorator. In this case, an error is reported because no base class has declared
|
4169
4283
|
// a method of the same name.
|
@@ -4192,7 +4306,7 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
4192
4306
|
this._evaluator.addDiagnostic(this._fileInfo.diagnosticRuleSet.reportGeneralTypeIssues, diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, localize_1.Localizer.Diagnostic.overriddenMethodNotFound().format({ name: funcNode.name.value }), funcNode.name);
|
4193
4307
|
}
|
4194
4308
|
_validateBaseClassOverride(baseClassAndSymbol, overrideSymbol, overrideType, childClassType, memberName) {
|
4195
|
-
var _a, _b;
|
4309
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
4196
4310
|
if (!(0, types_1.isInstantiableClass)(baseClassAndSymbol.classType)) {
|
4197
4311
|
return;
|
4198
4312
|
}
|
@@ -4216,8 +4330,32 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
4216
4330
|
overrideType = (0, typeUtils_1.partiallySpecializeType)(overrideType, childClassType, childClassSelf);
|
4217
4331
|
if ((0, types_1.isFunction)(baseType) || (0, types_1.isOverloadedFunction)(baseType)) {
|
4218
4332
|
const diagAddendum = new diagnostic_1.DiagnosticAddendum();
|
4333
|
+
// Determine whether this is an attempt to override a method marked @final.
|
4334
|
+
let reportFinalMethodOverride = false;
|
4335
|
+
// Private names (starting with double underscore) are exempt from this check.
|
4336
|
+
if (!SymbolNameUtils.isPrivateName(memberName)) {
|
4337
|
+
if ((0, types_1.isFunction)(baseType) && types_1.FunctionType.isFinal(baseType)) {
|
4338
|
+
reportFinalMethodOverride = true;
|
4339
|
+
}
|
4340
|
+
else if ((0, types_1.isOverloadedFunction)(baseType) &&
|
4341
|
+
baseType.overloads.some((overload) => types_1.FunctionType.isFinal(overload))) {
|
4342
|
+
reportFinalMethodOverride = true;
|
4343
|
+
}
|
4344
|
+
}
|
4345
|
+
if (reportFinalMethodOverride) {
|
4346
|
+
const decl = (0, symbolUtils_1.getLastTypedDeclaredForSymbol)(overrideSymbol);
|
4347
|
+
if (decl && decl.type === 5 /* DeclarationType.Function */) {
|
4348
|
+
const diag = this._evaluator.addError(localize_1.Localizer.Diagnostic.finalMethodOverride().format({
|
4349
|
+
name: memberName,
|
4350
|
+
className: baseClass.details.name,
|
4351
|
+
}), decl.node.name);
|
4352
|
+
const origDecl = (0, symbolUtils_1.getLastTypedDeclaredForSymbol)(baseClassAndSymbol.symbol);
|
4353
|
+
if (diag && origDecl) {
|
4354
|
+
diag.addRelatedInfo(localize_1.Localizer.DiagnosticAddendum.finalMethod(), origDecl.uri, origDecl.range);
|
4355
|
+
}
|
4356
|
+
}
|
4357
|
+
}
|
4219
4358
|
if ((0, types_1.isFunction)(overrideType) || (0, types_1.isOverloadedFunction)(overrideType)) {
|
4220
|
-
const exemptMethods = ['__init__', '__new__', '__init_subclass__'];
|
4221
4359
|
// Don't enforce parameter names for dundered methods. Many of them
|
4222
4360
|
// are misnamed in typeshed stubs, so this would result in many
|
4223
4361
|
// false positives.
|
@@ -4226,7 +4364,7 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
4226
4364
|
// Also, skip this check if the class is a TypedDict. The methods for a TypedDict
|
4227
4365
|
// are synthesized, and they can result in many overloads. We assume they
|
4228
4366
|
// are correct and will not produce any errors.
|
4229
|
-
if (!
|
4367
|
+
if (!this._isMethodExemptFromLsp(memberName) &&
|
4230
4368
|
!SymbolNameUtils.isPrivateName(memberName) &&
|
4231
4369
|
!types_1.ClassType.isTypedDictClass(childClassType)) {
|
4232
4370
|
if (!this._evaluator.validateOverrideMethod(baseType, overrideType, childClassType, diagAddendum, enforceParamNameMatch)) {
|
@@ -4237,7 +4375,7 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
4237
4375
|
const diag = this._evaluator.addDiagnostic(this._fileInfo.diagnosticRuleSet.reportIncompatibleMethodOverride, diagnosticRules_1.DiagnosticRule.reportIncompatibleMethodOverride, localize_1.Localizer.Diagnostic.incompatibleMethodOverride().format({
|
4238
4376
|
name: memberName,
|
4239
4377
|
className: baseClass.details.name,
|
4240
|
-
}) + diagAddendum.getString(), decl
|
4378
|
+
}) + diagAddendum.getString(), (_a = (0, declarationUtils_1.getNameNodeForDeclaration)(decl)) !== null && _a !== void 0 ? _a : decl.node);
|
4241
4379
|
const origDecl = (0, symbolUtils_1.getLastTypedDeclaredForSymbol)(baseClassAndSymbol.symbol);
|
4242
4380
|
if (diag && origDecl) {
|
4243
4381
|
diag.addRelatedInfo(localize_1.Localizer.DiagnosticAddendum.overriddenMethod(), origDecl.uri, origDecl.range);
|
@@ -4245,22 +4383,6 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
4245
4383
|
}
|
4246
4384
|
}
|
4247
4385
|
}
|
4248
|
-
if ((0, types_1.isFunction)(baseType)) {
|
4249
|
-
// Private names (starting with double underscore) are exempt from this check.
|
4250
|
-
if (!SymbolNameUtils.isPrivateName(memberName) && types_1.FunctionType.isFinal(baseType)) {
|
4251
|
-
const decl = (0, symbolUtils_1.getLastTypedDeclaredForSymbol)(overrideSymbol);
|
4252
|
-
if (decl && decl.type === 5 /* DeclarationType.Function */) {
|
4253
|
-
const diag = this._evaluator.addError(localize_1.Localizer.Diagnostic.finalMethodOverride().format({
|
4254
|
-
name: memberName,
|
4255
|
-
className: baseClass.details.name,
|
4256
|
-
}), decl.node.name);
|
4257
|
-
const origDecl = (0, symbolUtils_1.getLastTypedDeclaredForSymbol)(baseClassAndSymbol.symbol);
|
4258
|
-
if (diag && origDecl) {
|
4259
|
-
diag.addRelatedInfo(localize_1.Localizer.DiagnosticAddendum.finalMethod(), origDecl.uri, origDecl.range);
|
4260
|
-
}
|
4261
|
-
}
|
4262
|
-
}
|
4263
|
-
}
|
4264
4386
|
}
|
4265
4387
|
else if (!(0, types_1.isAnyOrUnknown)(overrideType)) {
|
4266
4388
|
// Special-case overrides of methods in '_TypedDict', since
|
@@ -4274,7 +4396,7 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
4274
4396
|
name: memberName,
|
4275
4397
|
className: baseClass.details.name,
|
4276
4398
|
type: this._evaluator.printType(overrideType),
|
4277
|
-
}), lastDecl.node);
|
4399
|
+
}), (_b = (0, declarationUtils_1.getNameNodeForDeclaration)(lastDecl)) !== null && _b !== void 0 ? _b : lastDecl.node);
|
4278
4400
|
const origDecl = (0, symbolUtils_1.getLastTypedDeclaredForSymbol)(baseClassAndSymbol.symbol);
|
4279
4401
|
if (diag && origDecl) {
|
4280
4402
|
diag.addRelatedInfo(localize_1.Localizer.DiagnosticAddendum.overriddenMethod(), origDecl.uri, origDecl.range);
|
@@ -4288,10 +4410,11 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
4288
4410
|
if (!(0, typeUtils_1.isProperty)(overrideType)) {
|
4289
4411
|
const decls = overrideSymbol.getDeclarations();
|
4290
4412
|
if (decls.length > 0) {
|
4413
|
+
const lastDecl = decls[decls.length - 1];
|
4291
4414
|
this._evaluator.addDiagnostic(this._fileInfo.diagnosticRuleSet.reportIncompatibleMethodOverride, diagnosticRules_1.DiagnosticRule.reportIncompatibleMethodOverride, localize_1.Localizer.Diagnostic.propertyOverridden().format({
|
4292
4415
|
name: memberName,
|
4293
4416
|
className: baseClass.details.name,
|
4294
|
-
}),
|
4417
|
+
}), (_c = (0, declarationUtils_1.getNameNodeForDeclaration)(lastDecl)) !== null && _c !== void 0 ? _c : lastDecl.node);
|
4295
4418
|
}
|
4296
4419
|
}
|
4297
4420
|
else {
|
@@ -4302,6 +4425,7 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
4302
4425
|
['fdel', (c) => { var _a; return (_a = c.fdelInfo) === null || _a === void 0 ? void 0 : _a.methodType; }],
|
4303
4426
|
];
|
4304
4427
|
propMethodInfo.forEach((info) => {
|
4428
|
+
var _a;
|
4305
4429
|
const diagAddendum = new diagnostic_1.DiagnosticAddendum();
|
4306
4430
|
const [methodName, methodAccessor] = info;
|
4307
4431
|
const baseClassPropMethod = methodAccessor(baseType);
|
@@ -4317,10 +4441,11 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
4317
4441
|
}));
|
4318
4442
|
const decls = overrideSymbol.getDeclarations();
|
4319
4443
|
if (decls.length > 0) {
|
4444
|
+
const lastDecl = decls[decls.length - 1];
|
4320
4445
|
const diag = this._evaluator.addDiagnostic(this._fileInfo.diagnosticRuleSet.reportIncompatibleMethodOverride, diagnosticRules_1.DiagnosticRule.reportIncompatibleMethodOverride, localize_1.Localizer.Diagnostic.propertyOverridden().format({
|
4321
4446
|
name: memberName,
|
4322
4447
|
className: baseClassType.details.name,
|
4323
|
-
}) + diagAddendum.getString(),
|
4448
|
+
}) + diagAddendum.getString(), (_a = (0, declarationUtils_1.getNameNodeForDeclaration)(lastDecl)) !== null && _a !== void 0 ? _a : lastDecl.node);
|
4324
4449
|
const origDecl = baseClassMethodType.details.declaration;
|
4325
4450
|
if (diag && origDecl) {
|
4326
4451
|
diag.addRelatedInfo(localize_1.Localizer.DiagnosticAddendum.overriddenMethod(), origDecl.uri, origDecl.range);
|
@@ -4398,7 +4523,7 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
4398
4523
|
const diag = this._evaluator.addDiagnostic(this._fileInfo.diagnosticRuleSet.reportIncompatibleVariableOverride, diagnosticRules_1.DiagnosticRule.reportIncompatibleVariableOverride, localize_1.Localizer.Diagnostic.symbolOverridden().format({
|
4399
4524
|
name: memberName,
|
4400
4525
|
className: baseClass.details.name,
|
4401
|
-
}) + diagAddendum.getString(), (
|
4526
|
+
}) + diagAddendum.getString(), (_d = (0, declarationUtils_1.getNameNodeForDeclaration)(lastDecl)) !== null && _d !== void 0 ? _d : lastDecl.node);
|
4402
4527
|
const origDecl = (0, symbolUtils_1.getLastTypedDeclaredForSymbol)(baseClassAndSymbol.symbol);
|
4403
4528
|
if (diag && origDecl) {
|
4404
4529
|
diag.addRelatedInfo(localize_1.Localizer.DiagnosticAddendum.overriddenSymbol(), origDecl.uri, origDecl.range);
|
@@ -4419,14 +4544,14 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
4419
4544
|
const message = overrideTDEntry.isRequired
|
4420
4545
|
? localize_1.Localizer.Diagnostic.typedDictFieldRequiredRedefinition
|
4421
4546
|
: localize_1.Localizer.Diagnostic.typedDictFieldNotRequiredRedefinition;
|
4422
|
-
this._evaluator.addDiagnostic(AnalyzerNodeInfo.getFileInfo(lastDecl.node).diagnosticRuleSet.reportGeneralTypeIssues, diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, message().format({ name: memberName }), lastDecl.node);
|
4547
|
+
this._evaluator.addDiagnostic(AnalyzerNodeInfo.getFileInfo(lastDecl.node).diagnosticRuleSet.reportGeneralTypeIssues, diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, message().format({ name: memberName }), (_e = (0, declarationUtils_1.getNameNodeForDeclaration)(lastDecl)) !== null && _e !== void 0 ? _e : lastDecl.node);
|
4423
4548
|
}
|
4424
4549
|
// Make sure that the derived class isn't marking a previously writable
|
4425
4550
|
// entry as read-only.
|
4426
4551
|
if (!overriddenTDEntry.isReadOnly && overrideTDEntry.isReadOnly) {
|
4427
4552
|
this._evaluator.addDiagnostic(AnalyzerNodeInfo.getFileInfo(lastDecl.node).diagnosticRuleSet.reportGeneralTypeIssues, diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, localize_1.Localizer.Diagnostic.typedDictFieldReadOnlyRedefinition().format({
|
4428
4553
|
name: memberName,
|
4429
|
-
}), lastDecl.node);
|
4554
|
+
}), (_f = (0, declarationUtils_1.getNameNodeForDeclaration)(lastDecl)) !== null && _f !== void 0 ? _f : lastDecl.node);
|
4430
4555
|
}
|
4431
4556
|
}
|
4432
4557
|
// Verify that there is not a Final mismatch.
|
@@ -4436,7 +4561,7 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
4436
4561
|
const diag = this._evaluator.addDiagnostic(this._fileInfo.diagnosticRuleSet.reportIncompatibleVariableOverride, diagnosticRules_1.DiagnosticRule.reportIncompatibleVariableOverride, localize_1.Localizer.Diagnostic.variableFinalOverride().format({
|
4437
4562
|
name: memberName,
|
4438
4563
|
className: baseClass.details.name,
|
4439
|
-
}), lastDecl.node);
|
4564
|
+
}), (_g = (0, declarationUtils_1.getNameNodeForDeclaration)(lastDecl)) !== null && _g !== void 0 ? _g : lastDecl.node);
|
4440
4565
|
if (diag) {
|
4441
4566
|
diag.addRelatedInfo(localize_1.Localizer.DiagnosticAddendum.overriddenSymbol(), overrideFinalVarDecl.uri, overrideFinalVarDecl.range);
|
4442
4567
|
}
|
@@ -4465,7 +4590,7 @@ class Checker extends parseTreeWalker_1.ParseTreeWalker {
|
|
4465
4590
|
const diag = this._evaluator.addDiagnostic(this._fileInfo.diagnosticRuleSet.reportIncompatibleVariableOverride, diagnosticRules_1.DiagnosticRule.reportIncompatibleVariableOverride, unformattedMessage.format({
|
4466
4591
|
name: memberName,
|
4467
4592
|
className: baseClass.details.name,
|
4468
|
-
}), (
|
4593
|
+
}), (_h = (0, declarationUtils_1.getNameNodeForDeclaration)(lastDecl)) !== null && _h !== void 0 ? _h : lastDecl.node);
|
4469
4594
|
const origDecl = (0, symbolUtils_1.getLastTypedDeclaredForSymbol)(baseClassAndSymbol.symbol);
|
4470
4595
|
if (diag && origDecl) {
|
4471
4596
|
diag.addRelatedInfo(localize_1.Localizer.DiagnosticAddendum.overriddenSymbol(), origDecl.uri, origDecl.range);
|