@zzzen/pyright-internal 1.2.0-dev.20240218 → 1.2.0-dev.20240225
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 +1 -0
- package/dist/analyzer/binder.js.map +1 -1
- package/dist/analyzer/checker.d.ts +1 -2
- package/dist/analyzer/checker.js +138 -49
- package/dist/analyzer/checker.js.map +1 -1
- package/dist/analyzer/dataClasses.js +6 -6
- package/dist/analyzer/dataClasses.js.map +1 -1
- package/dist/analyzer/decorators.js +6 -6
- package/dist/analyzer/decorators.js.map +1 -1
- package/dist/analyzer/enums.js +1 -1
- package/dist/analyzer/enums.js.map +1 -1
- package/dist/analyzer/importResolver.js +11 -3
- package/dist/analyzer/importResolver.js.map +1 -1
- package/dist/analyzer/importStatementUtils.js +2 -0
- package/dist/analyzer/importStatementUtils.js.map +1 -1
- package/dist/analyzer/namedTuples.js +1 -1
- package/dist/analyzer/namedTuples.js.map +1 -1
- package/dist/analyzer/parameterUtils.js +11 -1
- package/dist/analyzer/parameterUtils.js.map +1 -1
- package/dist/analyzer/patternMatching.js +3 -3
- package/dist/analyzer/patternMatching.js.map +1 -1
- package/dist/analyzer/properties.js +2 -2
- package/dist/analyzer/sourceFile.js +4 -4
- package/dist/analyzer/sourceFile.js.map +1 -1
- package/dist/analyzer/typeEvaluator.js +160 -98
- package/dist/analyzer/typeEvaluator.js.map +1 -1
- package/dist/analyzer/typeEvaluatorTypes.d.ts +1 -0
- package/dist/analyzer/typeGuards.js +5 -5
- package/dist/analyzer/typeGuards.js.map +1 -1
- package/dist/analyzer/typePrinter.js +1 -1
- package/dist/analyzer/typePrinter.js.map +1 -1
- package/dist/analyzer/typeUtils.js +4 -3
- package/dist/analyzer/typeUtils.js.map +1 -1
- package/dist/analyzer/typedDicts.d.ts +6 -3
- package/dist/analyzer/typedDicts.js +292 -65
- package/dist/analyzer/typedDicts.js.map +1 -1
- package/dist/analyzer/types.d.ts +31 -23
- package/dist/analyzer/types.js +59 -44
- package/dist/analyzer/types.js.map +1 -1
- package/dist/commands/dumpFileDebugInfoCommand.js +18 -18
- package/dist/commands/dumpFileDebugInfoCommand.js.map +1 -1
- package/dist/common/cancellationUtils.d.ts +4 -0
- package/dist/common/cancellationUtils.js +2 -1
- package/dist/common/cancellationUtils.js.map +1 -1
- package/dist/languageService/autoImporter.d.ts +1 -0
- package/dist/languageService/autoImporter.js +3 -1
- package/dist/languageService/autoImporter.js.map +1 -1
- package/dist/languageService/completionProvider.js +4 -4
- package/dist/languageService/completionProvider.js.map +1 -1
- package/dist/languageService/hoverProvider.js +1 -1
- package/dist/languageService/hoverProvider.js.map +1 -1
- package/dist/localization/localize.d.ts +30 -2
- package/dist/localization/localize.js +9 -2
- package/dist/localization/localize.js.map +1 -1
- package/dist/localization/package.nls.cs.json +6 -8
- package/dist/localization/package.nls.de.json +6 -8
- package/dist/localization/package.nls.en-us.json +18 -11
- package/dist/localization/package.nls.es.json +6 -8
- package/dist/localization/package.nls.fr.json +3 -5
- package/dist/localization/package.nls.it.json +6 -8
- package/dist/localization/package.nls.ja.json +7 -9
- package/dist/localization/package.nls.ko.json +6 -8
- package/dist/localization/package.nls.pl.json +6 -8
- package/dist/localization/package.nls.pt-br.json +3 -5
- package/dist/localization/package.nls.qps-ploc.json +0 -2
- package/dist/localization/package.nls.ru.json +3 -5
- package/dist/localization/package.nls.tr.json +6 -8
- package/dist/localization/package.nls.zh-cn.json +3 -5
- package/dist/localization/package.nls.zh-tw.json +6 -8
- package/dist/tests/checker.test.js +0 -4
- package/dist/tests/checker.test.js.map +1 -1
- package/dist/tests/harness/fourslash/testState.js +11 -0
- package/dist/tests/harness/fourslash/testState.js.map +1 -1
- package/dist/tests/importStatementUtils.test.js +8 -0
- package/dist/tests/importStatementUtils.test.js.map +1 -1
- package/dist/tests/typeEvaluator1.test.js +12 -0
- package/dist/tests/typeEvaluator1.test.js.map +1 -1
- package/dist/tests/typeEvaluator2.test.js +1 -1
- package/dist/tests/typeEvaluator3.test.js +4 -8
- package/dist/tests/typeEvaluator3.test.js.map +1 -1
- package/dist/tests/typeEvaluator5.test.js +42 -0
- package/dist/tests/typeEvaluator5.test.js.map +1 -1
- package/package.json +4 -4
- package/dist/analyzer/regions.d.ts +0 -11
- package/dist/analyzer/regions.js +0 -62
- package/dist/analyzer/regions.js.map +0 -1
@@ -32,7 +32,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
32
32
|
return result;
|
33
33
|
};
|
34
34
|
Object.defineProperty(exports, "__esModule", { value: true });
|
35
|
-
exports.narrowForKeyAssignment = exports.getTypeOfIndexedTypedDict = exports.assignToTypedDict = exports.assignTypedDictToTypedDict = exports.getTypedDictMembersForClass = exports.synthesizeTypedDictClassMethods = exports.createTypedDictTypeInlined = exports.createTypedDictType = void 0;
|
35
|
+
exports.narrowForKeyAssignment = exports.getTypeOfIndexedTypedDict = exports.assignToTypedDict = exports.assignTypedDictToTypedDict = exports.getEffectiveExtraItemsEntryType = exports.getTypedDictDictEquivalent = exports.getTypedDictMappingEquivalent = exports.getTypedDictMembersForClass = exports.synthesizeTypedDictClassMethods = exports.createTypedDictTypeInlined = exports.createTypedDictType = void 0;
|
36
36
|
const collectionUtils_1 = require("../common/collectionUtils");
|
37
37
|
const debug_1 = require("../common/debug");
|
38
38
|
const diagnostic_1 = require("../common/diagnostic");
|
@@ -49,7 +49,7 @@ const typeUtils_1 = require("./typeUtils");
|
|
49
49
|
const typeVarContext_1 = require("./typeVarContext");
|
50
50
|
// Creates a new custom TypedDict "alternate syntax" factory class.
|
51
51
|
function createTypedDictType(evaluator, errorNode, typedDictClass, argList) {
|
52
|
-
var _a, _b;
|
52
|
+
var _a, _b, _c;
|
53
53
|
const fileInfo = AnalyzerNodeInfo.getFileInfo(errorNode);
|
54
54
|
// TypedDict supports two different syntaxes:
|
55
55
|
// Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
|
@@ -70,7 +70,7 @@ function createTypedDictType(evaluator, errorNode, typedDictClass, argList) {
|
|
70
70
|
}
|
71
71
|
}
|
72
72
|
const effectiveClassName = className || 'TypedDict';
|
73
|
-
const classType = types_1.ClassType.createInstantiable(effectiveClassName, ParseTreeUtils.getClassFullName(errorNode, fileInfo.moduleName, effectiveClassName), fileInfo.moduleName, fileInfo.fileUri, 128 /* ClassTypeFlags.TypedDictClass */ |
|
73
|
+
const classType = types_1.ClassType.createInstantiable(effectiveClassName, ParseTreeUtils.getClassFullName(errorNode, fileInfo.moduleName, effectiveClassName), fileInfo.moduleName, fileInfo.fileUri, 128 /* ClassTypeFlags.TypedDictClass */ | 1073741824 /* ClassTypeFlags.ValidTypeAliasClass */, ParseTreeUtils.getTypeSourceId(errorNode),
|
74
74
|
/* declaredMetaclass */ undefined, typedDictClass.details.effectiveMetaclass);
|
75
75
|
classType.details.baseClasses.push(typedDictClass);
|
76
76
|
(0, typeUtils_1.computeMroLinearization)(classType);
|
@@ -122,7 +122,7 @@ function createTypedDictType(evaluator, errorNode, typedDictClass, argList) {
|
|
122
122
|
}
|
123
123
|
if (usingDictSyntax) {
|
124
124
|
for (const arg of argList.slice(2)) {
|
125
|
-
if (((_a = arg.name) === null || _a === void 0 ? void 0 : _a.value) === 'total') {
|
125
|
+
if (((_a = arg.name) === null || _a === void 0 ? void 0 : _a.value) === 'total' || ((_b = arg.name) === null || _b === void 0 ? void 0 : _b.value) === 'closed') {
|
126
126
|
if (!arg.valueExpression ||
|
127
127
|
arg.valueExpression.nodeType !== 11 /* ParseNodeType.Constant */ ||
|
128
128
|
!(arg.valueExpression.constType === 15 /* KeywordType.False */ ||
|
@@ -130,7 +130,13 @@ function createTypedDictType(evaluator, errorNode, typedDictClass, argList) {
|
|
130
130
|
evaluator.addDiagnostic(diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, localize_1.LocMessage.typedDictBoolParam().format({ name: arg.name.value }), arg.valueExpression || errorNode);
|
131
131
|
}
|
132
132
|
else if (arg.name.value === 'total' && arg.valueExpression.constType === 15 /* KeywordType.False */) {
|
133
|
-
classType.details.flags |=
|
133
|
+
classType.details.flags |= 1024 /* ClassTypeFlags.CanOmitDictValues */;
|
134
|
+
}
|
135
|
+
else if (arg.name.value === 'closed' && arg.valueExpression.constType === 33 /* KeywordType.True */) {
|
136
|
+
if (AnalyzerNodeInfo.getFileInfo(errorNode).diagnosticRuleSet.enableExperimentalFeatures) {
|
137
|
+
classType.details.flags |=
|
138
|
+
256 /* ClassTypeFlags.TypedDictMarkedClosed */ | 512 /* ClassTypeFlags.TypedDictEffectivelyClosed */;
|
139
|
+
}
|
134
140
|
}
|
135
141
|
}
|
136
142
|
else {
|
@@ -138,9 +144,9 @@ function createTypedDictType(evaluator, errorNode, typedDictClass, argList) {
|
|
138
144
|
}
|
139
145
|
}
|
140
146
|
}
|
141
|
-
synthesizeTypedDictClassMethods(evaluator, errorNode, classType
|
147
|
+
synthesizeTypedDictClassMethods(evaluator, errorNode, classType);
|
142
148
|
// Validate that the assigned variable name is consistent with the provided name.
|
143
|
-
if (((
|
149
|
+
if (((_c = errorNode.parent) === null || _c === void 0 ? void 0 : _c.nodeType) === 3 /* ParseNodeType.Assignment */ && className) {
|
144
150
|
const target = errorNode.parent.leftExpression;
|
145
151
|
const typedDictTarget = target.nodeType === 54 /* ParseNodeType.TypeAnnotation */ ? target.valueExpression : target;
|
146
152
|
if (typedDictTarget.nodeType === 38 /* ParseNodeType.Name */) {
|
@@ -163,11 +169,12 @@ function createTypedDictTypeInlined(evaluator, dictNode, typedDictClass) {
|
|
163
169
|
classType.details.baseClasses.push(typedDictClass);
|
164
170
|
(0, typeUtils_1.computeMroLinearization)(classType);
|
165
171
|
getTypedDictFieldsFromDictSyntax(evaluator, dictNode, classType.details.fields, /* isInline */ true);
|
166
|
-
synthesizeTypedDictClassMethods(evaluator, dictNode, classType
|
172
|
+
synthesizeTypedDictClassMethods(evaluator, dictNode, classType);
|
167
173
|
return classType;
|
168
174
|
}
|
169
175
|
exports.createTypedDictTypeInlined = createTypedDictTypeInlined;
|
170
|
-
function synthesizeTypedDictClassMethods(evaluator, node, classType
|
176
|
+
function synthesizeTypedDictClassMethods(evaluator, node, classType) {
|
177
|
+
var _a;
|
171
178
|
(0, debug_1.assert)(types_1.ClassType.isTypedDictClass(classType));
|
172
179
|
// Synthesize a __new__ method.
|
173
180
|
const newType = types_1.FunctionType.createSynthesizedInstance('__new__', 1 /* FunctionTypeFlags.ConstructorMethod */);
|
@@ -209,9 +216,9 @@ function synthesizeTypedDictClassMethods(evaluator, node, classType, isClassFina
|
|
209
216
|
// All parameters must be named, so insert an empty "*".
|
210
217
|
types_1.FunctionType.addKeywordOnlyParameterSeparator(initOverride2);
|
211
218
|
const entries = getTypedDictMembersForClass(evaluator, classType);
|
212
|
-
|
213
|
-
let allEntriesAreReadOnly =
|
214
|
-
entries.forEach((entry, name) => {
|
219
|
+
const extraEntriesInfo = (_a = entries.extraItems) !== null && _a !== void 0 ? _a : getEffectiveExtraItemsEntryType(evaluator, classType);
|
220
|
+
let allEntriesAreReadOnly = entries.knownItems.size > 0;
|
221
|
+
entries.knownItems.forEach((entry, name) => {
|
215
222
|
types_1.FunctionType.addParameter(initOverride1, {
|
216
223
|
category: 0 /* ParameterCategory.Simple */,
|
217
224
|
name,
|
@@ -226,13 +233,26 @@ function synthesizeTypedDictClassMethods(evaluator, node, classType, isClassFina
|
|
226
233
|
type: entry.valueType,
|
227
234
|
hasDeclaredType: true,
|
228
235
|
});
|
229
|
-
if (entry.isRequired) {
|
230
|
-
allEntriesAreNotRequired = false;
|
231
|
-
}
|
232
236
|
if (!entry.isReadOnly) {
|
233
237
|
allEntriesAreReadOnly = false;
|
234
238
|
}
|
235
239
|
});
|
240
|
+
if (entries.extraItems && !(0, types_1.isNever)(entries.extraItems.valueType)) {
|
241
|
+
types_1.FunctionType.addParameter(initOverride1, {
|
242
|
+
category: 2 /* ParameterCategory.KwargsDict */,
|
243
|
+
name: 'kwargs',
|
244
|
+
hasDefault: false,
|
245
|
+
type: entries.extraItems.valueType,
|
246
|
+
hasDeclaredType: true,
|
247
|
+
});
|
248
|
+
types_1.FunctionType.addParameter(initOverride2, {
|
249
|
+
category: 2 /* ParameterCategory.KwargsDict */,
|
250
|
+
name: 'kwargs',
|
251
|
+
hasDefault: false,
|
252
|
+
type: entries.extraItems.valueType,
|
253
|
+
hasDeclaredType: true,
|
254
|
+
});
|
255
|
+
}
|
236
256
|
const symbolTable = classType.details.fields;
|
237
257
|
const initType = types_1.OverloadedFunctionType.create([initOverride1, initOverride2]);
|
238
258
|
symbolTable.set('__init__', symbol_1.Symbol.createWithType(4 /* SymbolFlags.ClassMember */, initType));
|
@@ -389,7 +409,7 @@ function synthesizeTypedDictClassMethods(evaluator, node, classType, isClassFina
|
|
389
409
|
updateMethod3.details.declaredReturnType = evaluator.getNoneType();
|
390
410
|
const tuplesToCombine = [];
|
391
411
|
const tupleClass = evaluator.getBuiltInType(node, 'tuple');
|
392
|
-
entries.forEach((entry, name) => {
|
412
|
+
entries.knownItems.forEach((entry, name) => {
|
393
413
|
if (!entry.isReadOnly) {
|
394
414
|
// For writable entries, add a tuple entry.
|
395
415
|
if (tupleClass && (0, types_1.isInstantiableClass)(tupleClass) && strClass && (0, types_1.isInstantiableClass)(strClass)) {
|
@@ -433,7 +453,7 @@ function synthesizeTypedDictClassMethods(evaluator, node, classType, isClassFina
|
|
433
453
|
const getOverloads = [];
|
434
454
|
const popOverloads = [];
|
435
455
|
const setDefaultOverloads = [];
|
436
|
-
entries.forEach((entry, name) => {
|
456
|
+
entries.knownItems.forEach((entry, name) => {
|
437
457
|
const nameLiteralType = types_1.ClassType.cloneAsInstance(types_1.ClassType.cloneWithLiteral(strClass, name));
|
438
458
|
getOverloads.push(createGetMethod(nameLiteralType, entry.valueType, /* includeDefault */ false, entry.isRequired));
|
439
459
|
getOverloads.push(createGetMethod(nameLiteralType, entry.valueType,
|
@@ -448,9 +468,9 @@ function synthesizeTypedDictClassMethods(evaluator, node, classType, isClassFina
|
|
448
468
|
setDefaultOverloads.push(createSetDefaultMethod(nameLiteralType, entry.valueType));
|
449
469
|
}
|
450
470
|
});
|
451
|
-
// If the class is
|
471
|
+
// If the class is closed, we can assume that any other literal
|
452
472
|
// key values will return the default parameter value.
|
453
|
-
if (
|
473
|
+
if (types_1.ClassType.isTypedDictEffectivelyClosed(classType) && (0, types_1.isNever)(extraEntriesInfo.valueType)) {
|
454
474
|
const literalStringType = evaluator.getTypingType(node, 'LiteralString');
|
455
475
|
if (literalStringType && (0, types_1.isInstantiableClass)(literalStringType)) {
|
456
476
|
const literalStringInstance = types_1.ClassType.cloneAsInstance(literalStringType);
|
@@ -476,9 +496,10 @@ function synthesizeTypedDictClassMethods(evaluator, node, classType, isClassFina
|
|
476
496
|
symbolTable.set('__delitem__', symbol_1.Symbol.createWithType(4 /* SymbolFlags.ClassMember */, createDelItemMethod(strType)));
|
477
497
|
}
|
478
498
|
symbolTable.set('update', symbol_1.Symbol.createWithType(4 /* SymbolFlags.ClassMember */, createUpdateMethod()));
|
479
|
-
// If the TypedDict is
|
480
|
-
// add a "clear" and "popitem" method.
|
481
|
-
|
499
|
+
// If the TypedDict is closed and all of its entries are NotRequired and
|
500
|
+
// not ReadOnly, add a "clear" and "popitem" method.
|
501
|
+
const dictValueType = getTypedDictDictEquivalent(evaluator, classType);
|
502
|
+
if (dictValueType) {
|
482
503
|
const clearMethod = types_1.FunctionType.createSynthesizedInstance('clear');
|
483
504
|
types_1.FunctionType.addParameter(clearMethod, selfParam);
|
484
505
|
clearMethod.details.declaredReturnType = evaluator.getNoneType();
|
@@ -489,7 +510,7 @@ function synthesizeTypedDictClassMethods(evaluator, node, classType, isClassFina
|
|
489
510
|
if (tupleType && (0, types_1.isInstantiableClass)(tupleType)) {
|
490
511
|
tupleType = (0, typeUtils_1.specializeTupleClass)(types_1.ClassType.cloneAsInstance(tupleType), [
|
491
512
|
{ type: strType, isUnbounded: false },
|
492
|
-
{ type:
|
513
|
+
{ type: dictValueType, isUnbounded: false },
|
493
514
|
],
|
494
515
|
/* isTypeArgumentExplicit */ true);
|
495
516
|
}
|
@@ -499,21 +520,50 @@ function synthesizeTypedDictClassMethods(evaluator, node, classType, isClassFina
|
|
499
520
|
popItemMethod.details.declaredReturnType = tupleType;
|
500
521
|
symbolTable.set('popitem', symbol_1.Symbol.createWithType(4 /* SymbolFlags.ClassMember */, popItemMethod));
|
501
522
|
}
|
523
|
+
// If the TypedDict is closed, we can provide a more accurate value type
|
524
|
+
// for the "items", "keys" and "values" methods.
|
525
|
+
const mappingValueType = getTypedDictMappingEquivalent(evaluator, classType);
|
526
|
+
if (mappingValueType) {
|
527
|
+
['items', 'keys', 'values'].forEach((methodName) => {
|
528
|
+
const method = types_1.FunctionType.createSynthesizedInstance(methodName);
|
529
|
+
types_1.FunctionType.addParameter(method, selfParam);
|
530
|
+
const returnTypeClass = evaluator.getTypingType(node, `dict_${methodName}`);
|
531
|
+
if (returnTypeClass &&
|
532
|
+
(0, types_1.isInstantiableClass)(returnTypeClass) &&
|
533
|
+
returnTypeClass.details.typeParameters.length === 2) {
|
534
|
+
method.details.declaredReturnType = types_1.ClassType.cloneForSpecialization(types_1.ClassType.cloneAsInstance(returnTypeClass), [strType, mappingValueType],
|
535
|
+
/* isTypeArgumentExplicit */ true);
|
536
|
+
symbolTable.set(methodName, symbol_1.Symbol.createWithType(4 /* SymbolFlags.ClassMember */, method));
|
537
|
+
}
|
538
|
+
});
|
539
|
+
}
|
502
540
|
}
|
503
541
|
}
|
504
542
|
exports.synthesizeTypedDictClassMethods = synthesizeTypedDictClassMethods;
|
505
543
|
function getTypedDictMembersForClass(evaluator, classType, allowNarrowed = false) {
|
544
|
+
var _a;
|
506
545
|
// Were the entries already calculated and cached?
|
507
546
|
if (!classType.details.typedDictEntries) {
|
508
|
-
const entries =
|
547
|
+
const entries = {
|
548
|
+
knownItems: new Map(),
|
549
|
+
extraItems: undefined,
|
550
|
+
};
|
509
551
|
getTypedDictMembersForClassRecursive(evaluator, classType, entries);
|
552
|
+
if (types_1.ClassType.isTypedDictMarkedClosed(classType) && !entries.extraItems) {
|
553
|
+
entries.extraItems = {
|
554
|
+
valueType: types_1.NeverType.createNever(),
|
555
|
+
isReadOnly: false,
|
556
|
+
isRequired: false,
|
557
|
+
isProvided: false,
|
558
|
+
};
|
559
|
+
}
|
510
560
|
// Cache the entries for next time.
|
511
561
|
classType.details.typedDictEntries = entries;
|
512
562
|
}
|
513
563
|
const typeVarContext = (0, typeUtils_1.buildTypeVarContextFromSpecializedClass)(classType);
|
514
564
|
// Create a specialized copy of the entries so the caller can mutate them.
|
515
565
|
const entries = new Map();
|
516
|
-
classType.details.typedDictEntries.forEach((value, key) => {
|
566
|
+
classType.details.typedDictEntries.knownItems.forEach((value, key) => {
|
517
567
|
const tdEntry = { ...value };
|
518
568
|
tdEntry.valueType = (0, typeUtils_1.applySolvedTypeVars)(tdEntry.valueType, typeVarContext);
|
519
569
|
// If the class is "Partial", make all entries optional and convert all
|
@@ -537,9 +587,72 @@ function getTypedDictMembersForClass(evaluator, classType, allowNarrowed = false
|
|
537
587
|
entries.set(key, tdEntry);
|
538
588
|
});
|
539
589
|
}
|
540
|
-
return
|
590
|
+
return {
|
591
|
+
knownItems: entries,
|
592
|
+
extraItems: (_a = classType.details.typedDictEntries) === null || _a === void 0 ? void 0 : _a.extraItems,
|
593
|
+
};
|
541
594
|
}
|
542
595
|
exports.getTypedDictMembersForClass = getTypedDictMembersForClass;
|
596
|
+
// If the TypedDict class is consistent with Mapping[str, T] where T
|
597
|
+
// is some type other than object, it returns T. Otherwise it returns undefined.
|
598
|
+
function getTypedDictMappingEquivalent(evaluator, classType) {
|
599
|
+
(0, debug_1.assert)((0, types_1.isInstantiableClass)(classType));
|
600
|
+
(0, debug_1.assert)(types_1.ClassType.isTypedDictClass(classType));
|
601
|
+
// If the TypedDict class isn't closed, it's just a normal Mapping[str, object].
|
602
|
+
if (!types_1.ClassType.isTypedDictEffectivelyClosed(classType)) {
|
603
|
+
return undefined;
|
604
|
+
}
|
605
|
+
const entries = getTypedDictMembersForClass(evaluator, classType);
|
606
|
+
const typesToCombine = [];
|
607
|
+
entries.knownItems.forEach((entry) => {
|
608
|
+
typesToCombine.push(entry.valueType);
|
609
|
+
});
|
610
|
+
if (entries.extraItems) {
|
611
|
+
typesToCombine.push(entries.extraItems.valueType);
|
612
|
+
}
|
613
|
+
// Is the final value type 'object'?
|
614
|
+
const valueType = (0, types_1.combineTypes)(typesToCombine);
|
615
|
+
if ((0, types_1.isClassInstance)(valueType) && types_1.ClassType.isBuiltIn(valueType, 'object')) {
|
616
|
+
return undefined;
|
617
|
+
}
|
618
|
+
return valueType;
|
619
|
+
}
|
620
|
+
exports.getTypedDictMappingEquivalent = getTypedDictMappingEquivalent;
|
621
|
+
// If the TypedDict class is consistent with dict[str, T], it returns T.
|
622
|
+
// Otherwise it returns undefined.
|
623
|
+
function getTypedDictDictEquivalent(evaluator, classType, recursionCount = 0) {
|
624
|
+
(0, debug_1.assert)((0, types_1.isInstantiableClass)(classType));
|
625
|
+
(0, debug_1.assert)(types_1.ClassType.isTypedDictClass(classType));
|
626
|
+
// If the TypedDict class isn't closed, it's not equivalent to a dict.
|
627
|
+
if (!types_1.ClassType.isTypedDictEffectivelyClosed(classType)) {
|
628
|
+
return undefined;
|
629
|
+
}
|
630
|
+
const entries = getTypedDictMembersForClass(evaluator, classType);
|
631
|
+
// If there is no "extraItems" defined or it is read-only, it's not
|
632
|
+
// equivalent to a dict.
|
633
|
+
if (!entries.extraItems || entries.extraItems.isReadOnly) {
|
634
|
+
return undefined;
|
635
|
+
}
|
636
|
+
let dictValueType = entries.extraItems.valueType;
|
637
|
+
let isEquivalentToDict = true;
|
638
|
+
entries.knownItems.forEach((entry) => {
|
639
|
+
if (entry.isReadOnly || entry.isRequired) {
|
640
|
+
isEquivalentToDict = false;
|
641
|
+
}
|
642
|
+
dictValueType = (0, types_1.combineTypes)([dictValueType, entry.valueType]);
|
643
|
+
if (!evaluator.assignType(dictValueType, entry.valueType,
|
644
|
+
/* diag */ undefined,
|
645
|
+
/* destTypeVarContext */ undefined,
|
646
|
+
/* srcTypeVarContext */ undefined, 1 /* AssignTypeFlags.EnforceInvariance */, recursionCount + 1)) {
|
647
|
+
isEquivalentToDict = false;
|
648
|
+
}
|
649
|
+
});
|
650
|
+
if (!isEquivalentToDict) {
|
651
|
+
return undefined;
|
652
|
+
}
|
653
|
+
return dictValueType;
|
654
|
+
}
|
655
|
+
exports.getTypedDictDictEquivalent = getTypedDictDictEquivalent;
|
543
656
|
function getTypedDictFieldsFromDictSyntax(evaluator, entryDict, classFields, isInline) {
|
544
657
|
const entrySet = new Set();
|
545
658
|
const fileInfo = AnalyzerNodeInfo.getFileInfo(entryDict);
|
@@ -581,7 +694,7 @@ function getTypedDictFieldsFromDictSyntax(evaluator, entryDict, classFields, isI
|
|
581
694
|
// get evaluated again.
|
582
695
|
evaluator.setTypeResultForNode(entryDict, { type: types_1.UnknownType.create() });
|
583
696
|
}
|
584
|
-
function getTypedDictMembersForClassRecursive(evaluator, classType,
|
697
|
+
function getTypedDictMembersForClassRecursive(evaluator, classType, entries, recursionCount = 0) {
|
585
698
|
(0, debug_1.assert)(types_1.ClassType.isTypedDictClass(classType));
|
586
699
|
if (recursionCount > types_1.maxTypeRecursionCount) {
|
587
700
|
return;
|
@@ -593,7 +706,7 @@ function getTypedDictMembersForClassRecursive(evaluator, classType, keyMap, recu
|
|
593
706
|
(0, debug_1.assert)((0, types_1.isClass)(specializedBaseClassType));
|
594
707
|
// Recursively gather keys from parent classes. Don't report any errors
|
595
708
|
// in these cases because they will be reported within that class.
|
596
|
-
getTypedDictMembersForClassRecursive(evaluator, specializedBaseClassType,
|
709
|
+
getTypedDictMembersForClassRecursive(evaluator, specializedBaseClassType, entries, recursionCount);
|
597
710
|
}
|
598
711
|
});
|
599
712
|
const typeVarContext = (0, typeUtils_1.buildTypeVarContextFromSpecializedClass)(classType);
|
@@ -605,48 +718,79 @@ function getTypedDictMembersForClassRecursive(evaluator, classType, keyMap, recu
|
|
605
718
|
if (lastDecl && lastDecl.type === 1 /* DeclarationType.Variable */) {
|
606
719
|
let valueType = evaluator.getEffectiveTypeOfSymbol(symbol);
|
607
720
|
valueType = (0, typeUtils_1.applySolvedTypeVars)(valueType, typeVarContext);
|
721
|
+
const allowRequired = !types_1.ClassType.isTypedDictMarkedClosed(classType) || name !== '__extra_items__';
|
608
722
|
let isRequired = !types_1.ClassType.isCanOmitDictValues(classType);
|
609
723
|
let isReadOnly = false;
|
610
|
-
if (isRequiredTypedDictVariable(evaluator, symbol)) {
|
724
|
+
if (isRequiredTypedDictVariable(evaluator, symbol, allowRequired)) {
|
611
725
|
isRequired = true;
|
612
726
|
}
|
613
|
-
else if (isNotRequiredTypedDictVariable(evaluator, symbol)) {
|
727
|
+
else if (isNotRequiredTypedDictVariable(evaluator, symbol, allowRequired)) {
|
614
728
|
isRequired = false;
|
615
729
|
}
|
616
730
|
if (isReadOnlyTypedDictVariable(evaluator, symbol)) {
|
617
731
|
isReadOnly = true;
|
618
732
|
}
|
619
|
-
|
733
|
+
const tdEntry = {
|
620
734
|
valueType,
|
621
735
|
isReadOnly,
|
622
736
|
isRequired,
|
623
737
|
isProvided: false,
|
624
|
-
}
|
738
|
+
};
|
739
|
+
if (types_1.ClassType.isTypedDictMarkedClosed(classType) && name === '__extra_items__') {
|
740
|
+
tdEntry.isRequired = false;
|
741
|
+
entries.extraItems = tdEntry;
|
742
|
+
}
|
743
|
+
else {
|
744
|
+
entries.knownItems.set(name, tdEntry);
|
745
|
+
}
|
625
746
|
}
|
626
747
|
}
|
627
748
|
});
|
628
749
|
}
|
750
|
+
function getEffectiveExtraItemsEntryType(evaluator, classType) {
|
751
|
+
var _a;
|
752
|
+
(0, debug_1.assert)(types_1.ClassType.isTypedDictClass(classType));
|
753
|
+
// Missing entries in a non-closed TypedDict class are implicitly typed as
|
754
|
+
// ReadOnly[NotRequired[object]].
|
755
|
+
if (!types_1.ClassType.isTypedDictMarkedClosed(classType)) {
|
756
|
+
return {
|
757
|
+
valueType: evaluator.getObjectType(),
|
758
|
+
isReadOnly: true,
|
759
|
+
isRequired: false,
|
760
|
+
isProvided: false,
|
761
|
+
};
|
762
|
+
}
|
763
|
+
if ((_a = classType.details.typedDictEntries) === null || _a === void 0 ? void 0 : _a.extraItems) {
|
764
|
+
return classType.details.typedDictEntries.extraItems;
|
765
|
+
}
|
766
|
+
return {
|
767
|
+
valueType: types_1.NeverType.createNever(),
|
768
|
+
isReadOnly: true,
|
769
|
+
isRequired: false,
|
770
|
+
isProvided: false,
|
771
|
+
};
|
772
|
+
}
|
773
|
+
exports.getEffectiveExtraItemsEntryType = getEffectiveExtraItemsEntryType;
|
629
774
|
function assignTypedDictToTypedDict(evaluator, destType, srcType, diag, typeVarContext, flags, recursionCount = 0) {
|
775
|
+
var _a, _b;
|
630
776
|
let typesAreConsistent = true;
|
631
777
|
const destEntries = getTypedDictMembersForClass(evaluator, destType);
|
632
778
|
const srcEntries = getTypedDictMembersForClass(evaluator, srcType, /* allowNarrowed */ true);
|
633
|
-
|
634
|
-
|
779
|
+
const extraSrcEntries = (_a = srcEntries.extraItems) !== null && _a !== void 0 ? _a : getEffectiveExtraItemsEntryType(evaluator, srcType);
|
780
|
+
destEntries.knownItems.forEach((destEntry, name) => {
|
781
|
+
const srcEntry = srcEntries.knownItems.get(name);
|
635
782
|
if (!srcEntry) {
|
636
783
|
if (destEntry.isRequired || !destEntry.isReadOnly) {
|
637
784
|
diag === null || diag === void 0 ? void 0 : diag.createAddendum().addMessage(localize_1.LocAddendum.typedDictFieldMissing().format({
|
638
785
|
name,
|
639
|
-
type: evaluator.printType(srcType),
|
786
|
+
type: evaluator.printType(types_1.ClassType.cloneAsInstance(srcType)),
|
640
787
|
}));
|
641
788
|
typesAreConsistent = false;
|
642
789
|
}
|
643
790
|
else {
|
644
|
-
|
645
|
-
// so we need to make sure the dest entry is compatible with that.
|
646
|
-
const objType = evaluator.getObjectType();
|
647
|
-
if ((0, types_1.isClassInstance)(objType)) {
|
791
|
+
if ((0, types_1.isClassInstance)(extraSrcEntries.valueType)) {
|
648
792
|
const subDiag = diag === null || diag === void 0 ? void 0 : diag.createAddendum();
|
649
|
-
if (!evaluator.assignType(destEntry.valueType,
|
793
|
+
if (!evaluator.assignType(destEntry.valueType, extraSrcEntries.valueType, subDiag === null || subDiag === void 0 ? void 0 : subDiag.createAddendum(), typeVarContext,
|
650
794
|
/* srcTypeVarContext */ undefined, flags, recursionCount)) {
|
651
795
|
subDiag === null || subDiag === void 0 ? void 0 : subDiag.addMessage(localize_1.LocAddendum.memberTypeMismatch().format({ name }));
|
652
796
|
typesAreConsistent = false;
|
@@ -661,30 +805,85 @@ function assignTypedDictToTypedDict(evaluator, destType, srcType, diag, typeVarC
|
|
661
805
|
: localize_1.LocAddendum.typedDictFieldNotRequired();
|
662
806
|
diag === null || diag === void 0 ? void 0 : diag.createAddendum().addMessage(message.format({
|
663
807
|
name,
|
664
|
-
type: evaluator.printType(destType),
|
808
|
+
type: evaluator.printType(types_1.ClassType.cloneAsInstance(destType)),
|
665
809
|
}));
|
666
810
|
typesAreConsistent = false;
|
667
811
|
}
|
668
812
|
if (!destEntry.isReadOnly && srcEntry.isReadOnly) {
|
669
813
|
diag === null || diag === void 0 ? void 0 : diag.createAddendum().addMessage(localize_1.LocAddendum.typedDictFieldNotReadOnly().format({
|
670
814
|
name,
|
671
|
-
type: evaluator.printType(destType),
|
815
|
+
type: evaluator.printType(types_1.ClassType.cloneAsInstance(destType)),
|
672
816
|
}));
|
673
817
|
typesAreConsistent = false;
|
674
818
|
}
|
675
819
|
const subDiag = diag === null || diag === void 0 ? void 0 : diag.createAddendum();
|
676
|
-
let adjustedFlags = flags;
|
677
|
-
// If the dest field is not read-only, we need to enforce invariance.
|
678
|
-
if (!destEntry.isReadOnly) {
|
679
|
-
adjustedFlags |= 1 /* AssignTypeFlags.EnforceInvariance */;
|
680
|
-
}
|
681
820
|
if (!evaluator.assignType(destEntry.valueType, srcEntry.valueType, subDiag === null || subDiag === void 0 ? void 0 : subDiag.createAddendum(), typeVarContext,
|
682
|
-
/* srcTypeVarContext */ undefined,
|
821
|
+
/* srcTypeVarContext */ undefined, destEntry.isReadOnly ? flags : flags | 1 /* AssignTypeFlags.EnforceInvariance */, recursionCount)) {
|
683
822
|
subDiag === null || subDiag === void 0 ? void 0 : subDiag.addMessage(localize_1.LocAddendum.memberTypeMismatch().format({ name }));
|
684
823
|
typesAreConsistent = false;
|
685
824
|
}
|
686
825
|
}
|
687
826
|
});
|
827
|
+
// If the destination TypedDict is closed, check any extra entries in the source
|
828
|
+
// TypedDict to ensure that they don't violate the "extra items" type.
|
829
|
+
if (types_1.ClassType.isTypedDictEffectivelyClosed(destType)) {
|
830
|
+
const extraDestEntries = (_b = destEntries.extraItems) !== null && _b !== void 0 ? _b : getEffectiveExtraItemsEntryType(evaluator, destType);
|
831
|
+
srcEntries.knownItems.forEach((srcEntry, name) => {
|
832
|
+
// Have we already checked this item in the loop above?
|
833
|
+
if (destEntries.knownItems.has(name)) {
|
834
|
+
return;
|
835
|
+
}
|
836
|
+
if (!destEntries.extraItems) {
|
837
|
+
const subDiag = diag === null || diag === void 0 ? void 0 : diag.createAddendum();
|
838
|
+
subDiag === null || subDiag === void 0 ? void 0 : subDiag.addMessage(localize_1.LocAddendum.typedDictExtraFieldNotAllowed().format({
|
839
|
+
name,
|
840
|
+
type: evaluator.printType(types_1.ClassType.cloneAsInstance(destType)),
|
841
|
+
}));
|
842
|
+
typesAreConsistent = false;
|
843
|
+
}
|
844
|
+
else {
|
845
|
+
if (srcEntry.isRequired && !destEntries.extraItems.isReadOnly) {
|
846
|
+
diag === null || diag === void 0 ? void 0 : diag.createAddendum().addMessage(localize_1.LocAddendum.typedDictFieldNotRequired().format({
|
847
|
+
name,
|
848
|
+
type: evaluator.printType(types_1.ClassType.cloneAsInstance(destType)),
|
849
|
+
}));
|
850
|
+
typesAreConsistent = false;
|
851
|
+
}
|
852
|
+
const subDiag = diag === null || diag === void 0 ? void 0 : diag.createAddendum();
|
853
|
+
if (!evaluator.assignType(destEntries.extraItems.valueType, srcEntry.valueType, subDiag === null || subDiag === void 0 ? void 0 : subDiag.createAddendum(), typeVarContext,
|
854
|
+
/* srcTypeVarContext */ undefined, destEntries.extraItems.isReadOnly ? flags : flags | 1 /* AssignTypeFlags.EnforceInvariance */, recursionCount)) {
|
855
|
+
subDiag === null || subDiag === void 0 ? void 0 : subDiag.addMessage(localize_1.LocAddendum.typedDictExtraFieldTypeMismatch().format({
|
856
|
+
name,
|
857
|
+
type: evaluator.printType(types_1.ClassType.cloneAsInstance(destType)),
|
858
|
+
}));
|
859
|
+
typesAreConsistent = false;
|
860
|
+
}
|
861
|
+
else if (!destEntries.extraItems.isReadOnly && srcEntry.isReadOnly) {
|
862
|
+
diag === null || diag === void 0 ? void 0 : diag.createAddendum().addMessage(localize_1.LocAddendum.typedDictFieldNotReadOnly().format({
|
863
|
+
name,
|
864
|
+
type: evaluator.printType(types_1.ClassType.cloneAsInstance(srcType)),
|
865
|
+
}));
|
866
|
+
typesAreConsistent = false;
|
867
|
+
}
|
868
|
+
}
|
869
|
+
});
|
870
|
+
const subDiag = diag === null || diag === void 0 ? void 0 : diag.createAddendum();
|
871
|
+
if (!evaluator.assignType(extraDestEntries.valueType, extraSrcEntries.valueType, subDiag === null || subDiag === void 0 ? void 0 : subDiag.createAddendum(), typeVarContext,
|
872
|
+
/* srcTypeVarContext */ undefined, extraDestEntries.isReadOnly ? flags : flags | 1 /* AssignTypeFlags.EnforceInvariance */, recursionCount)) {
|
873
|
+
subDiag === null || subDiag === void 0 ? void 0 : subDiag.addMessage(localize_1.LocAddendum.typedDictExtraFieldTypeMismatch().format({
|
874
|
+
name: '__extra_items__',
|
875
|
+
type: evaluator.printType(types_1.ClassType.cloneAsInstance(srcType)),
|
876
|
+
}));
|
877
|
+
typesAreConsistent = false;
|
878
|
+
}
|
879
|
+
else if (!extraDestEntries.isReadOnly && extraSrcEntries.isReadOnly) {
|
880
|
+
diag === null || diag === void 0 ? void 0 : diag.createAddendum().addMessage(localize_1.LocAddendum.typedDictFieldNotReadOnly().format({
|
881
|
+
name: '__extra_items__',
|
882
|
+
type: evaluator.printType(types_1.ClassType.cloneAsInstance(destType)),
|
883
|
+
}));
|
884
|
+
typesAreConsistent = false;
|
885
|
+
}
|
886
|
+
}
|
688
887
|
return typesAreConsistent;
|
689
888
|
}
|
690
889
|
exports.assignTypedDictToTypedDict = assignTypedDictToTypedDict;
|
@@ -711,7 +910,7 @@ function assignToTypedDict(evaluator, classType, keyTypes, valueTypes, diagAdden
|
|
711
910
|
/* isTypeArgumentExplicit */ false);
|
712
911
|
}
|
713
912
|
}
|
714
|
-
const
|
913
|
+
const tdEntries = getTypedDictMembersForClass(evaluator, genericClassType);
|
715
914
|
keyTypes.forEach((keyTypeResult, index) => {
|
716
915
|
const keyType = keyTypeResult.type;
|
717
916
|
if (!(0, types_1.isClassInstance)(keyType) || !types_1.ClassType.isBuiltIn(keyType, 'str') || !(0, typeUtils_1.isLiteralType)(keyType)) {
|
@@ -719,17 +918,33 @@ function assignToTypedDict(evaluator, classType, keyTypes, valueTypes, diagAdden
|
|
719
918
|
}
|
720
919
|
else {
|
721
920
|
const keyValue = keyType.literalValue;
|
722
|
-
const symbolEntry =
|
921
|
+
const symbolEntry = tdEntries.knownItems.get(keyValue);
|
723
922
|
if (!symbolEntry) {
|
724
|
-
|
725
|
-
isMatch = false;
|
726
|
-
if (diagAddendum) {
|
923
|
+
if (tdEntries.extraItems) {
|
727
924
|
const subDiag = diagAddendum === null || diagAddendum === void 0 ? void 0 : diagAddendum.createAddendum();
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
925
|
+
if (!evaluator.assignType(tdEntries.extraItems.valueType, valueTypes[index].type, subDiag === null || subDiag === void 0 ? void 0 : subDiag.createAddendum(), typeVarContext,
|
926
|
+
/* srcTypeVarContext */ undefined, 256 /* AssignTypeFlags.RetainLiteralsForTypeVar */)) {
|
927
|
+
if (subDiag) {
|
928
|
+
subDiag.addMessage(localize_1.LocAddendum.typedDictFieldTypeMismatch().format({
|
929
|
+
name: '__extra_items__',
|
930
|
+
type: evaluator.printType(valueTypes[index].type),
|
931
|
+
}));
|
932
|
+
subDiag.addTextRange(keyTypeResult.node);
|
933
|
+
}
|
934
|
+
isMatch = false;
|
935
|
+
}
|
936
|
+
}
|
937
|
+
else {
|
938
|
+
// The provided key name doesn't exist.
|
939
|
+
isMatch = false;
|
940
|
+
if (diagAddendum) {
|
941
|
+
const subDiag = diagAddendum === null || diagAddendum === void 0 ? void 0 : diagAddendum.createAddendum();
|
942
|
+
subDiag.addMessage(localize_1.LocAddendum.typedDictFieldUndefined().format({
|
943
|
+
name: keyType.literalValue,
|
944
|
+
type: evaluator.printType(types_1.ClassType.cloneAsInstance(classType)),
|
945
|
+
}));
|
946
|
+
subDiag.addTextRange(keyTypeResult.node);
|
947
|
+
}
|
733
948
|
}
|
734
949
|
}
|
735
950
|
else {
|
@@ -762,7 +977,7 @@ function assignToTypedDict(evaluator, classType, keyTypes, valueTypes, diagAdden
|
|
762
977
|
return undefined;
|
763
978
|
}
|
764
979
|
// See if any required keys are missing.
|
765
|
-
|
980
|
+
tdEntries.knownItems.forEach((entry, name) => {
|
766
981
|
if (entry.isRequired && !entry.isProvided) {
|
767
982
|
if (diagAddendum) {
|
768
983
|
diagAddendum.addMessage(localize_1.LocAddendum.typedDictFieldRequired().format({
|
@@ -799,7 +1014,7 @@ function getTypeOfIndexedTypedDict(evaluator, node, baseType, usage) {
|
|
799
1014
|
let diag = new diagnostic_1.DiagnosticAddendum();
|
800
1015
|
let allDiagsInvolveNotRequiredKeys = true;
|
801
1016
|
const resultingType = (0, typeUtils_1.mapSubtypes)(indexType, (subtype) => {
|
802
|
-
var _a, _b;
|
1017
|
+
var _a, _b, _c;
|
803
1018
|
if ((0, types_1.isAnyOrUnknown)(subtype)) {
|
804
1019
|
return subtype;
|
805
1020
|
}
|
@@ -811,7 +1026,7 @@ function getTypeOfIndexedTypedDict(evaluator, node, baseType, usage) {
|
|
811
1026
|
}
|
812
1027
|
// Look up the entry in the typed dict to get its type.
|
813
1028
|
const entryName = subtype.literalValue;
|
814
|
-
const entry = entries.get(entryName);
|
1029
|
+
const entry = (_a = entries.knownItems.get(entryName)) !== null && _a !== void 0 ? _a : entries.extraItems;
|
815
1030
|
if (!entry) {
|
816
1031
|
diag.addMessage(localize_1.LocAddendum.keyUndefined().format({
|
817
1032
|
name: entryName,
|
@@ -835,7 +1050,7 @@ function getTypeOfIndexedTypedDict(evaluator, node, baseType, usage) {
|
|
835
1050
|
}));
|
836
1051
|
}
|
837
1052
|
if (usage.method === 'set') {
|
838
|
-
if (!evaluator.assignType(entry.valueType, (
|
1053
|
+
if (!evaluator.assignType(entry.valueType, (_c = (_b = usage.setType) === null || _b === void 0 ? void 0 : _b.type) !== null && _c !== void 0 ? _c : types_1.AnyType.create(), diag)) {
|
839
1054
|
allDiagsInvolveNotRequiredKeys = false;
|
840
1055
|
}
|
841
1056
|
}
|
@@ -885,7 +1100,7 @@ function narrowForKeyAssignment(classType, key) {
|
|
885
1100
|
if (!types_1.ClassType.isTypedDictClass(classType) || !classType.details.typedDictEntries) {
|
886
1101
|
return classType;
|
887
1102
|
}
|
888
|
-
const tdEntry = classType.details.typedDictEntries.get(key);
|
1103
|
+
const tdEntry = classType.details.typedDictEntries.knownItems.get(key);
|
889
1104
|
if (!tdEntry || tdEntry.isRequired) {
|
890
1105
|
return classType;
|
891
1106
|
}
|
@@ -905,7 +1120,7 @@ function narrowForKeyAssignment(classType, key) {
|
|
905
1120
|
return types_1.ClassType.cloneForNarrowedTypedDictEntries(classType, narrowedEntries);
|
906
1121
|
}
|
907
1122
|
exports.narrowForKeyAssignment = narrowForKeyAssignment;
|
908
|
-
function isRequiredTypedDictVariable(evaluator, symbol) {
|
1123
|
+
function isRequiredTypedDictVariable(evaluator, symbol, allowRequired) {
|
909
1124
|
return symbol.getDeclarations().some((decl) => {
|
910
1125
|
if (decl.type !== 1 /* DeclarationType.Variable */ || !decl.typeAnnotationNode) {
|
911
1126
|
return false;
|
@@ -914,10 +1129,16 @@ function isRequiredTypedDictVariable(evaluator, symbol) {
|
|
914
1129
|
allowFinal: true,
|
915
1130
|
allowRequired: true,
|
916
1131
|
});
|
1132
|
+
if (!allowRequired) {
|
1133
|
+
if (annotatedType.isRequired) {
|
1134
|
+
evaluator.addDiagnostic(diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, localize_1.LocMessage.requiredNotInTypedDict(), decl.typeAnnotationNode);
|
1135
|
+
}
|
1136
|
+
return false;
|
1137
|
+
}
|
917
1138
|
return !!annotatedType.isRequired;
|
918
1139
|
});
|
919
1140
|
}
|
920
|
-
function isNotRequiredTypedDictVariable(evaluator, symbol) {
|
1141
|
+
function isNotRequiredTypedDictVariable(evaluator, symbol, allowRequired) {
|
921
1142
|
return symbol.getDeclarations().some((decl) => {
|
922
1143
|
if (decl.type !== 1 /* DeclarationType.Variable */ || !decl.typeAnnotationNode) {
|
923
1144
|
return false;
|
@@ -926,6 +1147,12 @@ function isNotRequiredTypedDictVariable(evaluator, symbol) {
|
|
926
1147
|
allowFinal: true,
|
927
1148
|
allowRequired: true,
|
928
1149
|
});
|
1150
|
+
if (!allowRequired) {
|
1151
|
+
if (annotatedType.isNotRequired) {
|
1152
|
+
evaluator.addDiagnostic(diagnosticRules_1.DiagnosticRule.reportGeneralTypeIssues, localize_1.LocMessage.notRequiredNotInTypedDict(), decl.typeAnnotationNode);
|
1153
|
+
}
|
1154
|
+
return false;
|
1155
|
+
}
|
929
1156
|
return !!annotatedType.isNotRequired;
|
930
1157
|
});
|
931
1158
|
}
|