diff --git a/packages/pyright-internal/src/analyzer/typeEvaluator.ts b/packages/pyright-internal/src/analyzer/typeEvaluator.ts index c8b8f1b0b..1b51ec9bc 100644 --- a/packages/pyright-internal/src/analyzer/typeEvaluator.ts +++ b/packages/pyright-internal/src/analyzer/typeEvaluator.ts @@ -1038,7 +1038,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions case ParseNodeType.List: case ParseNodeType.Set: { - typeResult = getTypeOfListOrSet(node, inferenceContext); + typeResult = getTypeOfListOrSet(node, flags, inferenceContext); break; } @@ -1063,7 +1063,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions } case ParseNodeType.Dictionary: { - typeResult = getTypeOfDictionary(node, inferenceContext); + typeResult = getTypeOfDictionary(node, flags, inferenceContext); break; } @@ -7304,6 +7304,23 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions flags: EvaluatorFlags, inferenceContext: InferenceContext | undefined ): TypeResult { + if ( + (flags & EvaluatorFlags.ExpectingTypeAnnotation) !== 0 && + node.parent?.nodeType !== ParseNodeType.Argument + ) { + // This is allowed inside of an index trailer, specifically + // to support Tuple[()], which is the documented way to annotate + // a zero-length tuple. + const diag = new DiagnosticAddendum(); + diag.addMessage(Localizer.DiagnosticAddendum.useTupleInstead()); + addDiagnostic( + AnalyzerNodeInfo.getFileInfo(node).diagnosticRuleSet.reportGeneralTypeIssues, + DiagnosticRule.reportGeneralTypeIssues, + Localizer.Diagnostic.tupleInAnnotation() + diag.getString(), + node + ); + } + if ( (flags & EvaluatorFlags.ExpectingInstantiableType) !== 0 && node.expressions.length === 0 && @@ -7528,6 +7545,21 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions ): TypeResult { let baseTypeResult: TypeResult | undefined; + if ( + (flags & EvaluatorFlags.ExpectingTypeAnnotation) !== 0 && + node.leftExpression.nodeType === ParseNodeType.Name && + node.leftExpression.value === 'type' + ) { + const diag = new DiagnosticAddendum(); + diag.addMessage(Localizer.DiagnosticAddendum.useTypeInstead()); + addDiagnostic( + AnalyzerNodeInfo.getFileInfo(node).diagnosticRuleSet.reportGeneralTypeIssues, + DiagnosticRule.reportGeneralTypeIssues, + Localizer.Diagnostic.typeCallNotAllowed() + diag.getString(), + node + ); + } + // Handle immediate calls of lambdas specially. if (node.leftExpression.nodeType === ParseNodeType.Lambda) { baseTypeResult = getTypeOfLambdaForCall(node, inferenceContext); @@ -12251,7 +12283,25 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions return returnType; } - function getTypeOfDictionary(node: DictionaryNode, inferenceContext: InferenceContext | undefined): TypeResult { + function getTypeOfDictionary( + node: DictionaryNode, + flags: EvaluatorFlags, + inferenceContext: InferenceContext | undefined + ): TypeResult { + if ( + (flags & EvaluatorFlags.ExpectingTypeAnnotation) !== 0 && + node.parent?.nodeType !== ParseNodeType.Argument + ) { + const diag = new DiagnosticAddendum(); + diag.addMessage(Localizer.DiagnosticAddendum.useDictInstead()); + addDiagnostic( + AnalyzerNodeInfo.getFileInfo(node).diagnosticRuleSet.reportGeneralTypeIssues, + DiagnosticRule.reportGeneralTypeIssues, + Localizer.Diagnostic.dictInAnnotation() + diag.getString(), + node + ); + } + // If the expected type is a union, analyze for each of the subtypes // to find one that matches. let effectiveExpectedType = inferenceContext?.expectedType; @@ -12730,7 +12780,26 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions return isIncomplete; } - function getTypeOfListOrSet(node: ListNode | SetNode, inferenceContext: InferenceContext | undefined): TypeResult { + function getTypeOfListOrSet( + node: ListNode | SetNode, + flags: EvaluatorFlags, + inferenceContext: InferenceContext | undefined + ): TypeResult { + if ( + (flags & EvaluatorFlags.ExpectingTypeAnnotation) !== 0 && + node.nodeType === ParseNodeType.List && + node.parent?.nodeType !== ParseNodeType.Argument + ) { + const diag = new DiagnosticAddendum(); + diag.addMessage(Localizer.DiagnosticAddendum.useListInstead()); + addDiagnostic( + AnalyzerNodeInfo.getFileInfo(node).diagnosticRuleSet.reportGeneralTypeIssues, + DiagnosticRule.reportGeneralTypeIssues, + Localizer.Diagnostic.listInAnnotation() + diag.getString(), + node + ); + } + // If the expected type is a union, recursively call for each of the subtypes // to find one that matches. let effectiveExpectedType = inferenceContext?.expectedType; diff --git a/packages/pyright-internal/src/parser/parser.ts b/packages/pyright-internal/src/parser/parser.ts index bee068e87..341a6d10d 100644 --- a/packages/pyright-internal/src/parser/parser.ts +++ b/packages/pyright-internal/src/parser/parser.ts @@ -3436,14 +3436,6 @@ export class Parser { this._isParsingTypeAnnotation = wasParsingTypeAnnotation; - if (this._isParsingTypeAnnotation) { - const diag = new DiagnosticAddendum(); - if (atomExpression.nodeType === ParseNodeType.Name && atomExpression.value === 'type') { - diag.addMessage(Localizer.DiagnosticAddendum.useTypeInstead()); - this._addError(Localizer.Diagnostic.typeCallNotAllowed() + diag.getString(), callNode); - } - } - atomExpression = callNode; if (atomExpression.maxChildDepth !== undefined && atomExpression.maxChildDepth >= maxChildNodeDepth) { @@ -3818,18 +3810,6 @@ export class Parser { if (nextToken.type === TokenType.OpenParenthesis) { const possibleTupleNode = this._parseTupleAtom(); - if ( - possibleTupleNode.nodeType === ParseNodeType.Tuple && - this._isParsingTypeAnnotation && - !this._isParsingIndexTrailer - ) { - // This is allowed inside of an index trailer, specifically - // to support Tuple[()], which is the documented way to annotate - // a zero-length tuple. - const diag = new DiagnosticAddendum(); - diag.addMessage(Localizer.DiagnosticAddendum.useTupleInstead()); - this._addError(Localizer.Diagnostic.tupleInAnnotation() + diag.getString(), possibleTupleNode); - } if ( possibleTupleNode.nodeType === ParseNodeType.UnaryOperation || @@ -3853,21 +3833,9 @@ export class Parser { return possibleTupleNode; } else if (nextToken.type === TokenType.OpenBracket) { - const listNode = this._parseListAtom(); - if (this._isParsingTypeAnnotation && !this._isParsingIndexTrailer) { - const diag = new DiagnosticAddendum(); - diag.addMessage(Localizer.DiagnosticAddendum.useListInstead()); - this._addError(Localizer.Diagnostic.listInAnnotation() + diag.getString(), listNode); - } - return listNode; + return this._parseListAtom(); } else if (nextToken.type === TokenType.OpenCurlyBrace) { - const dictNode = this._parseDictionaryOrSetAtom(); - if (this._isParsingTypeAnnotation && !this._isParsingIndexTrailer) { - const diag = new DiagnosticAddendum(); - diag.addMessage(Localizer.DiagnosticAddendum.useDictInstead()); - this._addError(Localizer.Diagnostic.dictInAnnotation() + diag.getString(), dictNode); - } - return dictNode; + return this._parseDictionaryOrSetAtom(); } if (nextToken.type === TokenType.Keyword) { diff --git a/packages/pyright-internal/src/tests/typeEvaluator4.test.ts b/packages/pyright-internal/src/tests/typeEvaluator4.test.ts index 4d1017757..241a88fa9 100644 --- a/packages/pyright-internal/src/tests/typeEvaluator4.test.ts +++ b/packages/pyright-internal/src/tests/typeEvaluator4.test.ts @@ -910,7 +910,7 @@ test('ParamSpec19', () => { test('ParamSpec20', () => { const results = TestUtils.typeAnalyzeSampleFiles(['paramSpec20.py']); - TestUtils.validateResults(results, 6); + TestUtils.validateResults(results, 8); }); test('ParamSpec21', () => {