From 0992c5771484b21aec36a52668d296e7d9ea1193 Mon Sep 17 00:00:00 2001 From: detachhead Date: Mon, 12 Feb 2024 17:04:02 +1000 Subject: [PATCH] report partial `Any`s as well --- .../pyright-internal/src/analyzer/checker.ts | 128 ++++++++++++------ .../src/analyzer/patternMatching.ts | 39 ++++-- .../src/analyzer/typeEvaluator.ts | 92 ++++++++----- .../src/analyzer/typeUtils.ts | 30 ++-- .../src/localization/localize.ts | 10 ++ .../src/localization/package.nls.en-us.json | 6 + .../src/tests/reportAny.test.ts | 51 ------- .../src/tests/samples/reportAny.py | 6 +- .../src/tests/typeEvaluatorBased.test.ts | 55 ++++++++ 9 files changed, 270 insertions(+), 147 deletions(-) delete mode 100644 packages/pyright-internal/src/tests/reportAny.test.ts diff --git a/packages/pyright-internal/src/analyzer/checker.ts b/packages/pyright-internal/src/analyzer/checker.ts index ea4b9c1c5..f11dd7515 100644 --- a/packages/pyright-internal/src/analyzer/checker.ts +++ b/packages/pyright-internal/src/analyzer/checker.ts @@ -150,6 +150,7 @@ import { isLiteralType, isLiteralTypeOrUnion, isNoneInstance, + isPartlyAny, isPartlyUnknown, isProperty, isTupleClass, @@ -473,26 +474,34 @@ export class Checker extends ParseTreeWalker { LocMessage.paramTypeUnknown().format({ paramName: param.name.value }), param.name ); - } else if (isPartlyUnknown(paramType)) { - const diagAddendum = new DiagnosticAddendum(); - diagAddendum.addMessage( - LocAddendum.paramType().format({ - paramType: this._evaluator.printType(paramType, { expandTypeAlias: true }), - }) - ); - this._evaluator.addDiagnostic( - DiagnosticRule.reportUnknownParameterType, - LocMessage.paramTypePartiallyUnknown().format({ - paramName: param.name.value, - }) + diagAddendum.getString(), - param.name - ); } else if (isAny(paramType)) { this._evaluator.addDiagnostic( DiagnosticRule.reportAny, LocMessage.paramTypeAny().format({ paramName: param.name.value }), param.name ); + } else { + const partlyUnknown = isPartlyUnknown(paramType); + if (partlyUnknown || isPartlyAny(paramType)) { + const diagAddendum = new DiagnosticAddendum(); + diagAddendum.addMessage( + LocAddendum.paramType().format({ + paramType: this._evaluator.printType(paramType, { expandTypeAlias: true }), + }) + ); + this._evaluator.addDiagnostic( + partlyUnknown + ? DiagnosticRule.reportUnknownParameterType + : DiagnosticRule.reportAny, + (partlyUnknown + ? LocMessage.paramTypePartiallyUnknown() + : LocMessage.paramTypePartiallyAny() + ).format({ + paramName: param.name.value, + }) + diagAddendum.getString(), + param.name + ); + } } } @@ -763,6 +772,12 @@ export class Checker extends ParseTreeWalker { LocMessage.paramTypeAny().format({ paramName: param.name.value }), param.name ); + } else if (isPartlyAny(paramType)) { + this._evaluator.addDiagnostic( + DiagnosticRule.reportAny, + LocMessage.paramTypePartiallyAny().format({ paramName: param.name.value }), + param.name + ); } } } @@ -776,20 +791,32 @@ export class Checker extends ParseTreeWalker { LocMessage.lambdaReturnTypeUnknown(), node.expression ); - } else if (isPartlyUnknown(returnType)) { - this._evaluator.addDiagnostic( - DiagnosticRule.reportUnknownLambdaType, - LocMessage.lambdaReturnTypePartiallyUnknown().format({ - returnType: this._evaluator.printType(returnType, { expandTypeAlias: true }), - }), - node.expression - ); } else if (isAny(returnType)) { this._evaluator.addDiagnostic( DiagnosticRule.reportAny, LocMessage.lambdaReturnTypeAny(), node.expression ); + } else { + const partlyUnknown = isPartlyUnknown(returnType); + if (partlyUnknown || isPartlyAny(returnType)) { + const formatter = { + returnType: this._evaluator.printType(returnType, { expandTypeAlias: true }), + }; + if (partlyUnknown) { + this._evaluator.addDiagnostic( + DiagnosticRule.reportUnknownLambdaType, + LocMessage.lambdaReturnTypePartiallyUnknown().format(formatter), + node.expression + ); + } else { + this._evaluator.addDiagnostic( + DiagnosticRule.reportAny, + LocMessage.lambdaReturnTypePartiallyAny().format(formatter), + node.expression + ); + } + } } } @@ -1057,20 +1084,33 @@ export class Checker extends ParseTreeWalker { LocMessage.returnTypeUnknown(), node.returnExpression ?? node ); - } else if (isPartlyUnknown(returnType)) { - this._evaluator.addDiagnostic( - DiagnosticRule.reportUnknownVariableType, - LocMessage.returnTypePartiallyUnknown().format({ - returnType: this._evaluator.printType(returnType, { expandTypeAlias: true }), - }), - node.returnExpression ?? node - ); } else if (isAny(returnType)) { this._evaluator.addDiagnostic( DiagnosticRule.reportAny, LocMessage.returnTypeAny(), node.returnExpression ?? node ); + } else { + const partlyUnknown = isPartlyUnknown(returnType); + if (partlyUnknown || isPartlyAny(returnType)) { + const formatter = { + returnType: this._evaluator.printType(returnType, { expandTypeAlias: true }), + }; + const returnNode = node.returnExpression ?? node; + if (partlyUnknown) { + this._evaluator.addDiagnostic( + DiagnosticRule.reportUnknownVariableType, + LocMessage.returnTypePartiallyUnknown().format(formatter), + returnNode + ); + } else { + this._evaluator.addDiagnostic( + DiagnosticRule.reportAny, + LocMessage.returnTypePartiallyAny().format(formatter), + returnNode + ); + } + } } } @@ -4769,16 +4809,28 @@ export class Checker extends ParseTreeWalker { LocMessage.returnTypeUnknown(), node.name ); - } else if (isPartlyUnknown(returnType)) { - this._evaluator.addDiagnostic( - DiagnosticRule.reportUnknownParameterType, - LocMessage.returnTypePartiallyUnknown().format({ - returnType: this._evaluator.printType(returnType, { expandTypeAlias: true }), - }), - node.name - ); } else if (isAny(returnType)) { this._evaluator.addDiagnostic(DiagnosticRule.reportAny, LocMessage.returnTypeAny(), node.name); + } else { + const partlyUnknown = isPartlyUnknown(returnType); + if (partlyUnknown || isPartlyAny(returnType)) { + const formatter = { + returnType: this._evaluator.printType(returnType, { expandTypeAlias: true }), + }; + if (partlyUnknown) { + this._evaluator.addDiagnostic( + DiagnosticRule.reportUnknownParameterType, + LocMessage.returnTypePartiallyUnknown().format(formatter), + node.name + ); + } else { + this._evaluator.addDiagnostic( + DiagnosticRule.reportAny, + LocMessage.returnTypePartiallyAny().format(formatter), + node.name + ); + } + } } } diff --git a/packages/pyright-internal/src/analyzer/patternMatching.ts b/packages/pyright-internal/src/analyzer/patternMatching.ts index 54a2519be..260b4f850 100644 --- a/packages/pyright-internal/src/analyzer/patternMatching.ts +++ b/packages/pyright-internal/src/analyzer/patternMatching.ts @@ -72,6 +72,7 @@ import { isLiteralTypeOrUnion, isMetaclassInstance, isNoneInstance, + isPartlyAny, isPartlyUnknown, isTupleClass, isUnboundedTupleClass, @@ -1592,25 +1593,37 @@ export function assignTypeToPatternTargets( LocMessage.wildcardPatternTypeUnknown(), pattern.target ); - } else if (isPartlyUnknown(narrowedType)) { - const diagAddendum = new DiagnosticAddendum(); - diagAddendum.addMessage( - LocAddendum.typeOfSymbol().format({ - name: '_', - type: evaluator.printType(narrowedType, { expandTypeAlias: true }), - }) - ); - evaluator.addDiagnostic( - DiagnosticRule.reportUnknownVariableType, - LocMessage.wildcardPatternTypePartiallyUnknown() + diagAddendum.getString(), - pattern.target - ); } else if (isAny(narrowedType)) { evaluator.addDiagnostic( DiagnosticRule.reportAny, LocMessage.wildcardPatternTypeAny(), pattern.target ); + } else { + const partlyUnknown = isPartlyUnknown(narrowedType); + if (partlyUnknown || isPartlyAny(narrowedType)) { + const diagAddendum = new DiagnosticAddendum(); + diagAddendum.addMessage( + LocAddendum.typeOfSymbol().format({ + name: '_', + type: evaluator.printType(narrowedType, { expandTypeAlias: true }), + }) + ); + const addendum = diagAddendum.getString(); + if (partlyUnknown) { + evaluator.addDiagnostic( + DiagnosticRule.reportUnknownVariableType, + LocMessage.wildcardPatternTypePartiallyUnknown() + addendum, + pattern.target + ); + } else { + evaluator.addDiagnostic( + DiagnosticRule.reportAny, + LocMessage.wildcardPatternTypePartiallyAny() + addendum, + pattern.target + ); + } + } } } } else { diff --git a/packages/pyright-internal/src/analyzer/typeEvaluator.ts b/packages/pyright-internal/src/analyzer/typeEvaluator.ts index e40a28941..b47a397a9 100644 --- a/packages/pyright-internal/src/analyzer/typeEvaluator.ts +++ b/packages/pyright-internal/src/analyzer/typeEvaluator.ts @@ -240,6 +240,7 @@ import { isNoneInstance, isNoneTypeClass, isOptionalType, + isPartlyAny, isPartlyUnknown, isProperty, isTupleClass, @@ -12073,23 +12074,6 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions LocMessage.argTypeUnknown() + diagAddendum.getString(), argParam.errorNode ); - } else if (isPartlyUnknown(simplifiedType)) { - // If the parameter type is also partially unknown, don't report - // the error because it's likely that the partially-unknown type - // arose due to bidirectional type matching. - if (!isPartlyUnknown(argParam.paramType)) { - const diagAddendum = getDiagAddendum(); - diagAddendum.addMessage( - LocAddendum.argumentType().format({ - type: printType(simplifiedType, { expandTypeAlias: true }), - }) - ); - addDiagnostic( - DiagnosticRule.reportUnknownArgumentType, - LocMessage.argTypePartiallyUnknown() + diagAddendum.getString(), - argParam.errorNode - ); - } } else if (isAny(simplifiedType)) { const diagAddendum = getDiagAddendum(); addDiagnostic( @@ -12097,6 +12081,35 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions LocMessage.argTypeAny() + diagAddendum.getString(), argParam.errorNode ); + } else { + const partlyUnknown = isPartlyUnknown(simplifiedType); + if (partlyUnknown || isPartlyAny(simplifiedType)) { + // If the parameter type is also partially unknown, don't report + // the error because it's likely that the partially-unknown type + // arose due to bidirectional type matching. + if (!isPartlyUnknown(argParam.paramType)) { + const diagAddendum = getDiagAddendum(); + diagAddendum.addMessage( + LocAddendum.argumentType().format({ + type: printType(simplifiedType, { expandTypeAlias: true }), + }) + ); + const addendum = diagAddendum.getString(); + if (partlyUnknown) { + addDiagnostic( + DiagnosticRule.reportUnknownArgumentType, + LocMessage.argTypePartiallyUnknown() + addendum, + argParam.errorNode + ); + } else { + addDiagnostic( + DiagnosticRule.reportAny, + LocMessage.argTypePartiallyAny() + addendum, + argParam.errorNode + ); + } + } + } } } } @@ -14121,26 +14134,35 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions if (isUnknown(simplifiedType)) { addDiagnostic(rule, LocMessage.typeUnknown().format({ name: nameValue }), errorNode); - } else if (isPartlyUnknown(simplifiedType)) { - // If ignoreEmptyContainers is true, don't report the problem for - // empty containers (lists or dictionaries). We'll report the problem - // only if the assigned value is used later. - if (!ignoreEmptyContainers || !isClassInstance(type) || !type.isEmptyContainer) { - const diagAddendum = new DiagnosticAddendum(); - diagAddendum.addMessage( - LocAddendum.typeOfSymbol().format({ - name: nameValue, - type: printType(simplifiedType, { expandTypeAlias: true }), - }) - ); - addDiagnostic( - rule, - LocMessage.typePartiallyUnknown().format({ name: nameValue }) + diagAddendum.getString(), - errorNode - ); - } } else if (isAny(simplifiedType)) { addDiagnostic(DiagnosticRule.reportAny, LocMessage.typeAny().format({ name: nameValue }), errorNode); + } else { + const partlyUnknown = isPartlyUnknown(simplifiedType); + if (partlyUnknown || isPartlyAny(simplifiedType)) { + // If ignoreEmptyContainers is true, don't report the problem for + // empty containers (lists or dictionaries). We'll report the problem + // only if the assigned value is used later. + if (!ignoreEmptyContainers || !isClassInstance(type) || !type.isEmptyContainer) { + const diagAddendum = new DiagnosticAddendum(); + diagAddendum.addMessage( + LocAddendum.typeOfSymbol().format({ + name: nameValue, + type: printType(simplifiedType, { expandTypeAlias: true }), + }) + ); + const formatter = { name: nameValue }; + const addendum = diagAddendum.getString(); + if (partlyUnknown) { + addDiagnostic(rule, LocMessage.typePartiallyUnknown().format(formatter) + addendum, errorNode); + } else { + addDiagnostic( + DiagnosticRule.reportAny, + LocMessage.typePartiallyAny().format(formatter) + addendum, + errorNode + ); + } + } + } } } diff --git a/packages/pyright-internal/src/analyzer/typeUtils.ts b/packages/pyright-internal/src/analyzer/typeUtils.ts index cf6787f41..e82c9e4b0 100644 --- a/packages/pyright-internal/src/analyzer/typeUtils.ts +++ b/packages/pyright-internal/src/analyzer/typeUtils.ts @@ -2638,31 +2638,32 @@ export function containsAnyOrUnknown(type: Type, recurse: boolean): AnyType | Un return walker.anyOrUnknownType; } -// Determines if any part of the type contains "Unknown", including any type arguments. // This function does not use the TypeWalker because it is called very frequently, // and allocating a memory walker object for every call significantly increases // peak memory usage. -export function isPartlyUnknown(type: Type, recursionCount = 0): boolean { +function recursivelyCheckType(type: Type, predicate: (type: Type) => boolean, recursionCount = 0): boolean { if (recursionCount > maxTypeRecursionCount) { return false; } recursionCount++; - if (isUnknown(type)) { + if (predicate(type)) { return true; } // If this is a generic type alias, see if any of its type arguments // are either unspecified or are partially known. if (type.typeAliasInfo?.typeArguments) { - if (type.typeAliasInfo.typeArguments.some((typeArg) => isPartlyUnknown(typeArg, recursionCount))) { + if ( + type.typeAliasInfo.typeArguments.some((typeArg) => recursivelyCheckType(typeArg, predicate, recursionCount)) + ) { return true; } } // See if a union contains an unknown type. if (isUnion(type)) { - return findSubtype(type, (subtype) => isPartlyUnknown(subtype, recursionCount)) !== undefined; + return findSubtype(type, (subtype) => recursivelyCheckType(subtype, predicate, recursionCount)) !== undefined; } // See if an object or class has an unknown type argument. @@ -2678,7 +2679,7 @@ export function isPartlyUnknown(type: Type, recursionCount = 0): boolean { const typeArgs = type.tupleTypeArguments?.map((t) => t.type) || type.typeArguments; if (typeArgs) { for (const argType of typeArgs) { - if (isPartlyUnknown(argType, recursionCount)) { + if (recursivelyCheckType(argType, predicate, recursionCount)) { return true; } } @@ -2691,7 +2692,7 @@ export function isPartlyUnknown(type: Type, recursionCount = 0): boolean { // See if a function has an unknown type. if (isOverloadedFunction(type)) { return OverloadedFunctionType.getOverloads(type).some((overload) => { - return isPartlyUnknown(overload, recursionCount); + return recursivelyCheckType(overload, predicate, recursionCount); }); } @@ -2700,7 +2701,7 @@ export function isPartlyUnknown(type: Type, recursionCount = 0): boolean { // Ignore parameters such as "*" that have no name. if (type.details.parameters[i].name) { const paramType = FunctionType.getEffectiveParameterType(type, i); - if (isPartlyUnknown(paramType, recursionCount)) { + if (recursivelyCheckType(paramType, predicate, recursionCount)) { return true; } } @@ -2709,7 +2710,7 @@ export function isPartlyUnknown(type: Type, recursionCount = 0): boolean { if ( type.details.declaredReturnType && !FunctionType.isParamSpecValue(type) && - isPartlyUnknown(type.details.declaredReturnType, recursionCount) + recursivelyCheckType(type.details.declaredReturnType, predicate, recursionCount) ) { return true; } @@ -2720,6 +2721,17 @@ export function isPartlyUnknown(type: Type, recursionCount = 0): boolean { return false; } +/** + * Determines if any part of the type contains `Unknown`, including any type arguments. + */ +export const isPartlyUnknown = (type: Type, recursionCount?: number) => + recursivelyCheckType(type, isUnknown, recursionCount); + +/** + * Determines if any part of the type contains `Any`, including any type arguments. + */ +export const isPartlyAny = (type: Type, recursionCount?: number) => recursivelyCheckType(type, isAny, recursionCount); + // If the specified type is a generic class with a single type argument // that is a union, it "explodes" the class into a union of classes with // each element of the union - e.g. Foo[A | B] becomes Foo[A] | Foo[B]. diff --git a/packages/pyright-internal/src/localization/localize.ts b/packages/pyright-internal/src/localization/localize.ts index fdcf835cc..561320d47 100644 --- a/packages/pyright-internal/src/localization/localize.ts +++ b/packages/pyright-internal/src/localization/localize.ts @@ -231,6 +231,7 @@ export namespace Localizer { new ParameterizedString<{ expected: number }>(getRawString('Diagnostic.argPositionalExpectedCount')); export const argPositionalExpectedOne = () => getRawString('Diagnostic.argPositionalExpectedOne'); export const argTypePartiallyUnknown = () => getRawString('Diagnostic.argTypePartiallyUnknown'); + export const argTypePartiallyAny = () => getRawString('Diagnostic.argTypePartiallyAny'); export const argTypeUnknown = () => getRawString('Diagnostic.argTypeUnknown'); export const argTypeAny = () => getRawString('Diagnostic.argTypeAny'); export const assertAlwaysTrue = () => getRawString('Diagnostic.assertAlwaysTrue'); @@ -606,6 +607,8 @@ export namespace Localizer { new ParameterizedString<{ returnType: string }>( getRawString('Diagnostic.lambdaReturnTypePartiallyUnknown') ); + export const lambdaReturnTypePartiallyAny = () => + new ParameterizedString<{ returnType: string }>(getRawString('Diagnostic.lambdaReturnTypePartiallyAny')); export const listAssignmentMismatch = () => new ParameterizedString<{ type: string }>(getRawString('Diagnostic.listAssignmentMismatch')); export const listInAnnotation = () => getRawString('Diagnostic.listInAnnotation'); @@ -773,6 +776,8 @@ export namespace Localizer { new ParameterizedString<{ paramName: string }>(getRawString('Diagnostic.paramTypeUnknown')); export const paramTypeAny = () => new ParameterizedString<{ paramName: string }>(getRawString('Diagnostic.paramTypeAny')); + export const paramTypePartiallyAny = () => + new ParameterizedString<{ paramName: string }>(getRawString('Diagnostic.paramTypePartiallyAny')); export const paramAssignmentMismatch = () => new ParameterizedString<{ sourceType: string; paramType: string }>( getRawString('Diagnostic.paramAssignmentMismatch') @@ -852,6 +857,8 @@ export namespace Localizer { export const returnTypeAny = () => getRawString('Diagnostic.returnTypeAny'); export const returnTypePartiallyUnknown = () => new ParameterizedString<{ returnType: string }>(getRawString('Diagnostic.returnTypePartiallyUnknown')); + export const returnTypePartiallyAny = () => + new ParameterizedString<{ returnType: string }>(getRawString('Diagnostic.returnTypePartiallyAny')); export const revealLocalsArgs = () => getRawString('Diagnostic.revealLocalsArgs'); export const revealLocalsNone = () => getRawString('Diagnostic.revealLocalsNone'); export const revealTypeArgs = () => getRawString('Diagnostic.revealTypeArgs'); @@ -1027,6 +1034,8 @@ export namespace Localizer { ); export const typePartiallyUnknown = () => new ParameterizedString<{ name: string }>(getRawString('Diagnostic.typePartiallyUnknown')); + export const typePartiallyAny = () => + new ParameterizedString<{ name: string }>(getRawString('Diagnostic.typePartiallyAny')); export const typeUnknown = () => new ParameterizedString<{ name: string }>(getRawString('Diagnostic.typeUnknown')); export const typeAny = () => new ParameterizedString<{ name: string }>(getRawString('Diagnostic.typeAny')); @@ -1163,6 +1172,7 @@ export namespace Localizer { export const wildcardPatternTypeAny = () => getRawString('Diagnostic.wildcardPatternTypeAny'); export const wildcardPatternTypePartiallyUnknown = () => getRawString('Diagnostic.wildcardPatternTypePartiallyUnknown'); + export const wildcardPatternTypePartiallyAny = () => getRawString('Diagnostic.wildcardPatternTypePartiallyAny'); export const wildcardLibraryImport = () => getRawString('Diagnostic.wildcardLibraryImport'); export const yieldFromIllegal = () => getRawString('Diagnostic.yieldFromIllegal'); export const yieldFromOutsideAsync = () => getRawString('Diagnostic.yieldFromOutsideAsync'); diff --git a/packages/pyright-internal/src/localization/package.nls.en-us.json b/packages/pyright-internal/src/localization/package.nls.en-us.json index 41edfb481..3ea55bce9 100644 --- a/packages/pyright-internal/src/localization/package.nls.en-us.json +++ b/packages/pyright-internal/src/localization/package.nls.en-us.json @@ -19,6 +19,7 @@ "argPositionalExpectedCount": "Expected {expected} positional arguments", "argPositionalExpectedOne": "Expected 1 positional argument", "argTypePartiallyUnknown": "Argument type is partially unknown", + "argTypePartiallyAny": "Argument type is partially Any", "argTypeUnknown": "Argument type is unknown", "argTypeAny": "Argument type is Any", "assertAlwaysTrue": "Assert expression always evaluates to true", @@ -262,6 +263,7 @@ "lambdaReturnTypeUnknown": "Return type of lambda is unknown", "lambdaReturnTypeAny": "Return type of lambda is Any", "lambdaReturnTypePartiallyUnknown": "Return type of lambda, \"{returnType}\", is partially unknown", + "lambdaReturnTypePartiallyAny": "Return type of lambda, \"{returnType}\", is partially Any", "listAssignmentMismatch": "Expression with type \"{type}\" cannot be assigned to target list", "listInAnnotation": "List expression not allowed in type annotation", "literalUnsupportedType": "Type arguments for \"Literal\" must be None, a literal value (int, bool, str, or bytes), or an enum value", @@ -367,6 +369,7 @@ "paramTypeUnknown": "Type of parameter \"{paramName}\" is unknown", "paramTypeAny": "Type of parameter \"{paramName}\" is Any", "paramTypePartiallyUnknown": "Type of parameter \"{paramName}\" is partially unknown", + "paramTypePartiallyAny": "Type of parameter \"{paramName}\" is partially Any", "parenthesizedContextManagerIllegal": "Parentheses within \"with\" statement requires Python 3.9 or newer", "patternNeverMatches": "Pattern will never be matched for subject type \"{type}\"", "positionArgAfterNamedArg": "Positional argument cannot appear after keyword arguments", @@ -409,6 +412,7 @@ "returnTypeUnknown": "Return type is unknown", "returnTypeAny": "Return type is Any", "returnTypePartiallyUnknown": "Return type, \"{returnType}\", is partially unknown", + "returnTypePartiallyAny": "Return type, \"{returnType}\", is partially Any", "revealLocalsArgs": "Expected no arguments for \"reveal_locals\" call", "revealLocalsNone": "No locals in this scope", "revealTypeArgs": "Expected a single positional argument for \"reveal_type\" call", @@ -515,6 +519,7 @@ "typeParametersMissing": "At least one type parameter must be specified", "typeParameterNotDeclared": "Type parameter \"{name}\" is not included in the type parameter list for \"{container}\"", "typePartiallyUnknown": "Type of \"{name}\" is partially unknown", + "typePartiallyAny": "Type of \"{name}\" is partially Any", "typeUnknown": "Type of \"{name}\" is unknown", "typeAny": "Type of \"{name}\" is Any", "typeVarAssignedName": "TypeVar must be assigned to a variable named \"{name}\"", @@ -606,6 +611,7 @@ "wildcardPatternTypeUnknown": "Type captured by wildcard pattern is unknown", "wildcardPatternTypeAny": "Type captured by wildcard pattern is Any", "wildcardPatternTypePartiallyUnknown": "Type captured by wildcard pattern is partially unknown", + "wildcardPatternTypePartiallyAny": "Type captured by wildcard pattern is partially Any", "wildcardLibraryImport": "Wildcard import from a library not allowed", "yieldFromIllegal": "Use of \"yield from\" requires Python 3.3 or newer", "yieldFromOutsideAsync": "\"yield from\" not allowed in an async function", diff --git a/packages/pyright-internal/src/tests/reportAny.test.ts b/packages/pyright-internal/src/tests/reportAny.test.ts deleted file mode 100644 index f453a0adb..000000000 --- a/packages/pyright-internal/src/tests/reportAny.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { ConfigOptions } from '../common/configOptions'; -import { DiagnosticRule } from '../common/diagnosticRules'; -import { Uri } from '../common/uri/uri'; -import { LocMessage } from '../localization/localize'; -import { typeAnalyzeSampleFiles, validateResultsButBased } from './testUtils'; - -test('reportAny', () => { - const configOptions = new ConfigOptions(Uri.empty()); - configOptions.diagnosticRuleSet.reportAny = 'error'; - const analysisResults = typeAnalyzeSampleFiles(['reportAny.py'], configOptions); - - validateResultsButBased(analysisResults, { - errors: [ - { line: 0, code: DiagnosticRule.reportAny, message: LocMessage.typeAny().format({ name: 'Any' }) }, - { line: 3, code: DiagnosticRule.reportAny, message: LocMessage.returnTypeAny() }, - { - line: 3, - code: DiagnosticRule.reportAny, - message: LocMessage.paramTypeAny().format({ paramName: 'bar' }), - }, - { line: 4, code: DiagnosticRule.reportAny }, - { line: 5, code: DiagnosticRule.reportAny, message: LocMessage.returnTypeAny() }, - { line: 7, code: DiagnosticRule.reportAny, message: LocMessage.typeAny().format({ name: 'bar' }) }, - { - line: 9, - code: DiagnosticRule.reportAny, - message: LocMessage.classDecoratorTypeAny(), - }, - { - line: 10, - code: DiagnosticRule.reportAny, - message: LocMessage.baseClassAny(), - }, - { - line: 12, - code: DiagnosticRule.reportAny, - message: LocMessage.functionDecoratorTypeAny(), - }, - { - line: 15, - code: DiagnosticRule.reportAny, - message: LocMessage.lambdaReturnTypeAny(), - }, - { - line: 18, - code: DiagnosticRule.reportAny, - message: LocMessage.wildcardPatternTypeAny(), - }, - ], - }); -}); diff --git a/packages/pyright-internal/src/tests/samples/reportAny.py b/packages/pyright-internal/src/tests/samples/reportAny.py index 769eb54c1..87c25fdf6 100644 --- a/packages/pyright-internal/src/tests/samples/reportAny.py +++ b/packages/pyright-internal/src/tests/samples/reportAny.py @@ -17,4 +17,8 @@ def baz() -> None: ... match(bar): case _: - ... \ No newline at end of file + ... + +bat: list[Any] = [] + +print(bat) diff --git a/packages/pyright-internal/src/tests/typeEvaluatorBased.test.ts b/packages/pyright-internal/src/tests/typeEvaluatorBased.test.ts index b0c9e61d7..29469cd4f 100644 --- a/packages/pyright-internal/src/tests/typeEvaluatorBased.test.ts +++ b/packages/pyright-internal/src/tests/typeEvaluatorBased.test.ts @@ -1,6 +1,7 @@ import { BasedConfigOptions, ConfigOptions } from '../common/configOptions'; import { DiagnosticRule } from '../common/diagnosticRules'; import { Uri } from '../common/uri/uri'; +import { LocMessage } from '../localization/localize'; import { typeAnalyzeSampleFiles, validateResultsButBased } from './testUtils'; test('reportUnreachable', () => { @@ -40,3 +41,57 @@ test('default typeCheckingMode=all', () => { unusedCodes: [{ line: 102 }], }); }); + +test('reportAny', () => { + const configOptions = new ConfigOptions(Uri.empty()); + configOptions.diagnosticRuleSet.reportAny = 'error'; + const analysisResults = typeAnalyzeSampleFiles(['reportAny.py'], configOptions); + + validateResultsButBased(analysisResults, { + errors: [ + { line: 0, code: DiagnosticRule.reportAny, message: LocMessage.typeAny().format({ name: 'Any' }) }, + { line: 3, code: DiagnosticRule.reportAny, message: LocMessage.returnTypeAny() }, + { + line: 3, + code: DiagnosticRule.reportAny, + message: LocMessage.paramTypeAny().format({ paramName: 'bar' }), + }, + { line: 4, code: DiagnosticRule.reportAny }, + { line: 5, code: DiagnosticRule.reportAny, message: LocMessage.returnTypeAny() }, + { line: 7, code: DiagnosticRule.reportAny, message: LocMessage.typeAny().format({ name: 'bar' }) }, + { + line: 9, + code: DiagnosticRule.reportAny, + message: LocMessage.classDecoratorTypeAny(), + }, + { + line: 10, + code: DiagnosticRule.reportAny, + message: LocMessage.baseClassAny(), + }, + { + line: 12, + code: DiagnosticRule.reportAny, + message: LocMessage.functionDecoratorTypeAny(), + }, + { + line: 15, + code: DiagnosticRule.reportAny, + message: LocMessage.lambdaReturnTypeAny(), + }, + { + line: 18, + code: DiagnosticRule.reportAny, + message: LocMessage.wildcardPatternTypeAny(), + }, + { + line: 21, + code: DiagnosticRule.reportAny, + }, + { + line: 23, + code: DiagnosticRule.reportAny, + }, + ], + }); +});