diff --git a/docs/type-concepts-advanced.md b/docs/type-concepts-advanced.md index 40a6de5f49..2a938e1894 100644 --- a/docs/type-concepts-advanced.md +++ b/docs/type-concepts-advanced.md @@ -71,7 +71,7 @@ In addition to assignment-based type narrowing, Pyright supports the following t * `x[I] == V` and `x[I] != V` (where I and V are literal expressions and x is a known-length tuple that is distinguished by the index indicated by I) * `x[I] is B` and `x[I] is not B` (where I is a literal expression, B is a `bool` or enum literal, and x is a known-length tuple that is distinguished by the index indicated by I) * `x[I] is None` and `x[I] is not None` (where I is a literal expression and x is a known-length tuple that is distinguished by the index indicated by I) -* `len(x) == L` and `len(x) != L` (where x is tuple and L is an expression that evaluates to an int literal type) +* `len(x) == L`, `len(x) != L`, `len(x) < L`, etc. (where x is tuple and L is an expression that evaluates to an int literal type) * `x in y` or `x not in y` (where y is instance of list, set, frozenset, deque, tuple, dict, defaultdict, or OrderedDict) * `S in D` and `S not in D` (where S is a string literal and D is a TypedDict) * `isinstance(x, T)` (where T is a type or a tuple of types) diff --git a/lerna.json b/lerna.json index 3cf25a1cf6..2ae7ead3fd 100644 --- a/lerna.json +++ b/lerna.json @@ -2,7 +2,7 @@ "packages": [ "packages/*" ], - "version": "1.1.358", + "version": "1.1.359", "command": { "version": { "push": false, diff --git a/packages/pyright-internal/package-lock.json b/packages/pyright-internal/package-lock.json index 744008d01c..c4e01d92ac 100644 --- a/packages/pyright-internal/package-lock.json +++ b/packages/pyright-internal/package-lock.json @@ -1,12 +1,12 @@ { "name": "pyright-internal", - "version": "1.1.358", + "version": "1.1.359", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "pyright-internal", - "version": "1.1.358", + "version": "1.1.359", "license": "MIT", "dependencies": { "@actions/core": "^1.10.1", @@ -17,7 +17,7 @@ "chokidar": "^3.6.0", "command-line-args": "^5.2.1", "jsonc-parser": "^3.2.1", - "leven": "^3.1.0", + "leven": "3.1.0", "pyright-to-gitlab-ci": "^0.1.3", "source-map-support": "^0.5.21", "tmp": "^0.2.1", @@ -2537,7 +2537,6 @@ "version": "6.1.3", "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", - "license": "MIT", "dependencies": { "array-back": "^4.0.2", "chalk": "^2.4.2", @@ -2552,7 +2551,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -2564,7 +2562,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", - "license": "MIT", "engines": { "node": ">=8" } @@ -2573,7 +2570,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -2587,7 +2583,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "license": "MIT", "engines": { "node": ">=0.8.0" } @@ -2596,7 +2591,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "license": "MIT", "engines": { "node": ">=4" } @@ -2605,7 +2599,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -2617,7 +2610,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "license": "MIT", "engines": { "node": ">=8" } @@ -2786,7 +2778,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -4833,7 +4824,6 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/pyright-to-gitlab-ci/-/pyright-to-gitlab-ci-0.1.3.tgz", "integrity": "sha512-fojkoQGVbPYyTPHq6R8XsS6vcokLh1OJjxEA6DRisvv1rAaEe3OrwaJp1qdey5ML9szTM2pDv66VMuYz/ostdw==", - "license": "ISC", "dependencies": { "ts-command-line-args": "^2.4.2" }, @@ -4903,7 +4893,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", - "license": "MIT", "engines": { "node": ">=6" } @@ -5216,8 +5205,7 @@ "node_modules/string-format": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz", - "integrity": "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==", - "license": "WTFPL OR MIT" + "integrity": "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==" }, "node_modules/string-length": { "version": "4.0.2", @@ -5315,7 +5303,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", - "license": "MIT", "dependencies": { "array-back": "^4.0.1", "deep-extend": "~0.6.0", @@ -5330,7 +5317,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", - "license": "MIT", "engines": { "node": ">=8" } @@ -5339,7 +5325,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "license": "MIT", "engines": { "node": ">=8" } @@ -5489,7 +5474,6 @@ "version": "2.5.1", "resolved": "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz", "integrity": "sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==", - "license": "ISC", "dependencies": { "chalk": "^4.1.0", "command-line-args": "^5.1.1", @@ -5689,9 +5673,9 @@ } }, "node_modules/undici": { - "version": "5.28.3", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", - "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -6004,7 +5988,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", - "license": "MIT", "dependencies": { "reduce-flatten": "^2.0.0", "typical": "^5.2.0" @@ -6017,7 +6000,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "license": "MIT", "engines": { "node": ">=8" } @@ -10255,9 +10237,9 @@ "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==" }, "undici": { - "version": "5.28.3", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", - "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", "requires": { "@fastify/busboy": "^2.0.0" } diff --git a/packages/pyright-internal/package.json b/packages/pyright-internal/package.json index c8a8328f6b..33e2a6ae52 100644 --- a/packages/pyright-internal/package.json +++ b/packages/pyright-internal/package.json @@ -2,7 +2,7 @@ "name": "pyright-internal", "displayName": "pyright", "description": "Type checker for the Python language", - "version": "1.1.358", + "version": "1.1.359", "license": "MIT", "private": true, "files": [ @@ -27,7 +27,7 @@ "chokidar": "^3.6.0", "command-line-args": "^5.2.1", "jsonc-parser": "^3.2.1", - "leven": "^3.1.0", + "leven": "3.1.0", "pyright-to-gitlab-ci": "^0.1.3", "source-map-support": "^0.5.21", "tmp": "^0.2.1", diff --git a/packages/pyright-internal/src/analyzer/binder.ts b/packages/pyright-internal/src/analyzer/binder.ts index 9ddddaa051..6160b20d6c 100644 --- a/packages/pyright-internal/src/analyzer/binder.ts +++ b/packages/pyright-internal/src/analyzer/binder.ts @@ -3148,9 +3148,32 @@ export class Binder extends ParseTreeWalker { // Look for "X is Y" or "X is not Y". // Look for X == or X != + // Look for len(X) == or len(X) != return isLeftNarrowing; } + // Look for len(X) < , len(X) <= , len(X) > , len(X) >= . + if ( + expression.rightExpression.nodeType === ParseNodeType.Number && + expression.rightExpression.isInteger + ) { + if ( + expression.operator === OperatorType.LessThan || + expression.operator === OperatorType.LessThanOrEqual || + expression.operator === OperatorType.GreaterThan || + expression.operator === OperatorType.GreaterThanOrEqual + ) { + const isLeftNarrowing = this._isNarrowingExpression( + expression.leftExpression, + expressionList, + filterForNeverNarrowing, + /* isComplexExpression */ true + ); + + return isLeftNarrowing; + } + } + // Look for " in Y" or " not in Y". if (expression.operator === OperatorType.In || expression.operator === OperatorType.NotIn) { if ( diff --git a/packages/pyright-internal/src/analyzer/checker.ts b/packages/pyright-internal/src/analyzer/checker.ts index 7f231638b7..c27a7ecedf 100644 --- a/packages/pyright-internal/src/analyzer/checker.ts +++ b/packages/pyright-internal/src/analyzer/checker.ts @@ -115,7 +115,7 @@ import { SourceMapper, isStubFile } from './sourceMapper'; import { evaluateStaticBoolExpression } from './staticExpressions'; import { Symbol } from './symbol'; import * as SymbolNameUtils from './symbolNameUtils'; -import { getLastTypedDeclaredForSymbol } from './symbolUtils'; +import { getLastTypedDeclarationForSymbol } from './symbolUtils'; import { maxCodeComplexity } from './typeEvaluator'; import { FunctionArgument, @@ -3121,7 +3121,7 @@ export class Checker extends ParseTreeWalker { // If there's one or more declaration with a declared type, // all other declarations should match. The only exception is // for functions that have an overload. - const primaryDecl = getLastTypedDeclaredForSymbol(symbol); + const primaryDecl = getLastTypedDeclarationForSymbol(symbol); // If there's no declaration with a declared type, we're done. if (!primaryDecl) { @@ -5652,8 +5652,8 @@ export class Checker extends ParseTreeWalker { : undefined; let diag: Diagnostic | undefined; - const overrideDecl = getLastTypedDeclaredForSymbol(overrideClassAndSymbol.symbol); - const overriddenDecl = getLastTypedDeclaredForSymbol(overriddenClassAndSymbol.symbol); + const overrideDecl = getLastTypedDeclarationForSymbol(overrideClassAndSymbol.symbol); + const overriddenDecl = getLastTypedDeclarationForSymbol(overriddenClassAndSymbol.symbol); if (isFunction(overriddenType) || isOverloadedFunction(overriddenType)) { const diagAddendum = new DiagnosticAddendum(); @@ -5715,7 +5715,7 @@ export class Checker extends ParseTreeWalker { // This check can be expensive, so don't perform it if the corresponding // rule is disabled. if (this._fileInfo.diagnosticRuleSet.reportIncompatibleVariableOverride !== 'none') { - const primaryDecl = getLastTypedDeclaredForSymbol(overriddenClassAndSymbol.symbol); + const primaryDecl = getLastTypedDeclarationForSymbol(overriddenClassAndSymbol.symbol); let isInvariant = primaryDecl?.type === DeclarationType.Variable && !primaryDecl.isFinal; // If the entry is a member of a frozen dataclass, it is immutable, @@ -5831,7 +5831,7 @@ export class Checker extends ParseTreeWalker { // but subsequent ones are, an error should be reported. private _validateOverloadDecoratorConsistency(classType: ClassType) { ClassType.getSymbolTable(classType).forEach((symbol, name) => { - const primaryDecl = getLastTypedDeclaredForSymbol(symbol); + const primaryDecl = getLastTypedDeclarationForSymbol(symbol); if (!primaryDecl || primaryDecl.type !== DeclarationType.Function) { return; @@ -6223,7 +6223,7 @@ export class Checker extends ParseTreeWalker { } if (reportFinalMethodOverride) { - const decl = getLastTypedDeclaredForSymbol(overrideSymbol); + const decl = getLastTypedDeclarationForSymbol(overrideSymbol); if (decl && decl.type === DeclarationType.Function) { const diag = this._evaluator.addDiagnostic( DiagnosticRule.reportIncompatibleMethodOverride, @@ -6234,7 +6234,7 @@ export class Checker extends ParseTreeWalker { decl.node.name ); - const origDecl = getLastTypedDeclaredForSymbol(baseClassAndSymbol.symbol); + const origDecl = getLastTypedDeclarationForSymbol(baseClassAndSymbol.symbol); if (diag && origDecl) { diag.addRelatedInfo(LocAddendum.finalMethod(), origDecl.uri, origDecl.range); } @@ -6268,7 +6268,7 @@ export class Checker extends ParseTreeWalker { const decl = isFunction(overrideType) && overrideType.details.declaration ? overrideType.details.declaration - : getLastTypedDeclaredForSymbol(overrideSymbol); + : getLastTypedDeclarationForSymbol(overrideSymbol); if (decl) { const diag = this._evaluator.addDiagnostic( DiagnosticRule.reportIncompatibleMethodOverride, @@ -6279,7 +6279,7 @@ export class Checker extends ParseTreeWalker { getNameNodeForDeclaration(decl) ?? decl.node ); - const origDecl = getLastTypedDeclaredForSymbol(baseClassAndSymbol.symbol); + const origDecl = getLastTypedDeclarationForSymbol(baseClassAndSymbol.symbol); if (diag && origDecl) { diag.addRelatedInfo(LocAddendum.overriddenMethod(), origDecl.uri, origDecl.range); } @@ -6304,7 +6304,7 @@ export class Checker extends ParseTreeWalker { getNameNodeForDeclaration(lastDecl) ?? lastDecl.node ); - const origDecl = getLastTypedDeclaredForSymbol(baseClassAndSymbol.symbol); + const origDecl = getLastTypedDeclarationForSymbol(baseClassAndSymbol.symbol); if (diag && origDecl) { diag.addRelatedInfo(LocAddendum.overriddenMethod(), origDecl.uri, origDecl.range); } @@ -6502,7 +6502,7 @@ export class Checker extends ParseTreeWalker { getNameNodeForDeclaration(lastDecl) ?? lastDecl.node ); - const origDecl = getLastTypedDeclaredForSymbol(baseClassAndSymbol.symbol); + const origDecl = getLastTypedDeclarationForSymbol(baseClassAndSymbol.symbol); if (diag && origDecl) { diag.addRelatedInfo(LocAddendum.overriddenSymbol(), origDecl.uri, origDecl.range); } @@ -6600,7 +6600,7 @@ export class Checker extends ParseTreeWalker { getNameNodeForDeclaration(lastDecl) ?? lastDecl.node ); - const origDecl = getLastTypedDeclaredForSymbol(baseClassAndSymbol.symbol); + const origDecl = getLastTypedDeclarationForSymbol(baseClassAndSymbol.symbol); if (diag && origDecl) { diag.addRelatedInfo(LocAddendum.overriddenSymbol(), origDecl.uri, origDecl.range); } @@ -6823,6 +6823,23 @@ export class Checker extends ParseTreeWalker { return; } + // If this is an __init__ method, we need to specifically check for the + // use of class-scoped TypeVars, which are not allowed in this context + // according to the typing spec. + if (functionType.details.name === '__init__' && functionType.details.methodClass) { + const typeVars = getTypeVarArgumentsRecursive(paramInfo.type); + + if ( + typeVars.some((typeVar) => typeVar.scopeId === functionType.details.methodClass?.details.typeVarScopeId) + ) { + this._evaluator.addDiagnostic( + DiagnosticRule.reportGeneralTypeIssues, + LocMessage.initMethodSelfParamTypeVar(), + paramInfo.typeAnnotation + ); + } + } + // If this is a protocol class, the self and cls parameters can be bound // to something other than the class. if (ClassType.isProtocolClass(classType)) { diff --git a/packages/pyright-internal/src/analyzer/constraintSolver.ts b/packages/pyright-internal/src/analyzer/constraintSolver.ts index d5fae63188..0f96d1aeb9 100644 --- a/packages/pyright-internal/src/analyzer/constraintSolver.ts +++ b/packages/pyright-internal/src/analyzer/constraintSolver.ts @@ -944,6 +944,7 @@ function assignTypeToParamSpec( newFunction.details.docString = srcType.details.docString; newFunction.details.deprecatedMessage = srcType.details.deprecatedMessage; newFunction.details.paramSpec = srcType.details.paramSpec; + newFunction.details.methodClass = srcType.details.methodClass; let updateContextWithNewFunction = false; @@ -953,30 +954,41 @@ function assignTypeToParamSpec( // for comparison purposes. const existingFunction = convertParamSpecValueToType(existingType); - // Should we narrow the type? - if ( - evaluator.assignType( - existingFunction, - newFunction, - /* diag */ undefined, - /* destTypeVarContext */ undefined, - /* srcTypeVarContext */ undefined, - AssignTypeFlags.SkipFunctionReturnTypeCheck, - recursionCount - ) - ) { + const isNewNarrower = evaluator.assignType( + existingFunction, + newFunction, + /* diag */ undefined, + /* destTypeVarContext */ undefined, + /* srcTypeVarContext */ undefined, + AssignTypeFlags.SkipFunctionReturnTypeCheck, + recursionCount + ); + + const isNewWider = evaluator.assignType( + newFunction, + existingFunction, + /* diag */ undefined, + /* destTypeVarContext */ undefined, + /* srcTypeVarContext */ undefined, + AssignTypeFlags.SkipFunctionReturnTypeCheck, + recursionCount + ); + + // Should we widen the type? + if (isNewNarrower && isNewWider) { + // The new type is both a supertype and a subtype of the existing type. + // That means the two types are the same or one (or both) have the type + // "..." (which is the ParamSpec equivalent of "Any"). If only one has + // the type "...", we'll prefer the other one. This is analogous to + // what we do with regular TypeVars, where we prefer non-Any values. + if (!FunctionType.shouldSkipArgsKwargsCompatibilityCheck(newFunction)) { + updateContextWithNewFunction = true; + } else { + return; + } + } else if (isNewWider) { updateContextWithNewFunction = true; - } else if ( - evaluator.assignType( - newFunction, - existingFunction, - /* diag */ undefined, - /* destTypeVarContext */ undefined, - /* srcTypeVarContext */ undefined, - AssignTypeFlags.SkipFunctionReturnTypeCheck, - recursionCount - ) - ) { + } else if (isNewNarrower) { // The existing function is already narrower than the new function, so // no need to narrow it further. return; diff --git a/packages/pyright-internal/src/analyzer/constructors.ts b/packages/pyright-internal/src/analyzer/constructors.ts index 8eb3f93661..7d85188127 100644 --- a/packages/pyright-internal/src/analyzer/constructors.ts +++ b/packages/pyright-internal/src/analyzer/constructors.ts @@ -27,12 +27,15 @@ import { applySolvedTypeVars, buildTypeVarContextFromSpecializedClass, convertToInstance, + doForEachSignature, doForEachSubtype, ensureFunctionSignaturesAreUnique, + getTypeVarArgumentsRecursive, getTypeVarScopeId, isTupleClass, lookUpClassMember, mapSubtypes, + selfSpecializeClass, specializeTupleClass, transformPossibleRecursiveTypeAlias, } from './typeUtils'; @@ -46,8 +49,11 @@ import { Type, TypeVarType, UnknownType, + combineTypes, + findSubtype, isAny, isAnyOrUnknown, + isClass, isClassInstance, isFunction, isInstantiableClass, @@ -126,20 +132,10 @@ export function validateConstructorArguments( const metaclassReturnType = metaclassResult.returnType ?? UnknownType.create(); // If there a custom `__call__` method on the metaclass that returns - // something other than Any or an instance of the class, assume that it + // something other than an instance of the class, assume that it // overrides the normal `type.__call__` logic and don't perform the usual // __new__ and __init__ validation. - if ( - metaclassResult.argumentErrors || - isNever(metaclassReturnType) || - !evaluator.assignType(convertToInstance(type), metaclassReturnType) - ) { - return metaclassResult; - } - - // Handle the special case of an enum class, where the __new__ and __init__ - // methods are replaced at runtime by the metaclass. - if (ClassType.isEnumClass(type)) { + if (metaclassResult.argumentErrors || shouldSkipNewAndInitEvaluation(evaluator, type, metaclassReturnType)) { return metaclassResult; } } @@ -155,7 +151,7 @@ export function validateConstructorArguments( // If there is a constructor transform, evaluate all arguments speculatively // so we can later re-evaluate them in the context of the transform. - let returnResult = evaluator.useSpeculativeMode(useConstructorTransform ? errorNode : undefined, () => { + const returnResult = evaluator.useSpeculativeMode(useConstructorTransform ? errorNode : undefined, () => { return validateNewAndInitMethods( evaluator, errorNode, @@ -217,21 +213,6 @@ export function validateConstructorArguments( }); } - // Reconcile the metaclass __call__ return type and the __new__ return type. - // This is a heuristic because we have no way of knowing how these actually - // interact based on the method signatures alone. - if (metaclassResult?.returnType) { - // If the __new__ and __init__ methods returned `Any` or `Unknown` or `NoReturn`, - // use the metaclass return type instead. - if (!returnResult.returnType || isAnyOrUnknown(returnResult.returnType)) { - if (!isAnyOrUnknown(metaclassResult.returnType)) { - returnResult = { ...returnResult, returnType: metaclassResult.returnType }; - } - } else if (returnResult.returnType && isNever(returnResult.returnType)) { - returnResult = { ...returnResult, returnType: metaclassResult.returnType }; - } - } - return returnResult; } @@ -643,14 +624,12 @@ function validateFallbackConstructorCall( // It's OK if the argument list consists only of `*args` and `**kwargs`. if (argList.length > 0 && argList.some((arg) => arg.argumentCategory === ArgumentCategory.Simple)) { - if (!type.includeSubclasses) { - evaluator.addDiagnostic( - DiagnosticRule.reportCallIssue, - LocMessage.constructorNoArgs().format({ type: type.aliasName || type.details.name }), - errorNode - ); - reportedErrors = true; - } + evaluator.addDiagnostic( + DiagnosticRule.reportCallIssue, + LocMessage.constructorNoArgs().format({ type: type.aliasName || type.details.name }), + errorNode + ); + reportedErrors = true; } if (!inferenceContext && type.typeArguments) { @@ -804,14 +783,100 @@ export function createFunctionFromConstructor( classType: ClassType, selfType: ClassType | TypeVarType | undefined = undefined, recursionCount = 0 -): FunctionType | OverloadedFunctionType | undefined { - const fromInit = createFunctionFromInitMethod(evaluator, classType, selfType, recursionCount); - if (fromInit) { - return fromInit; +): Type | undefined { + const fromMetaclassCall = createFunctionFromMetaclassCall(evaluator, classType, recursionCount); + if (fromMetaclassCall) { + return fromMetaclassCall; } const fromNew = createFunctionFromNewMethod(evaluator, classType, selfType, recursionCount); - return fromNew; + + if (fromNew) { + let skipInitMethod = false; + + doForEachSignature(fromNew, (signature) => { + const newMethodReturnType = FunctionType.getSpecializedReturnType(signature); + if (newMethodReturnType && shouldSkipInitEvaluation(evaluator, classType, newMethodReturnType)) { + skipInitMethod = true; + } + }); + + if (skipInitMethod) { + return fromNew; + } + } + + const fromInit = createFunctionFromInitMethod(evaluator, classType, selfType, recursionCount); + + // If there is both a __new__ and __init__ method, return a union + // comprised of both resulting function types. + if (fromNew && fromInit) { + return combineTypes([fromInit, fromNew]); + } + + if (fromNew || fromInit) { + return fromNew ?? fromInit; + } + + return fromNew ?? createFunctionFromObjectNewMethod(classType); +} + +function createFunctionFromMetaclassCall( + evaluator: TypeEvaluator, + classType: ClassType, + recursionCount: number +): FunctionType | OverloadedFunctionType | undefined { + const metaclass = classType.details.effectiveMetaclass; + if (!metaclass || !isClass(metaclass)) { + return undefined; + } + + const callInfo = lookUpClassMember( + metaclass, + '__call__', + MemberAccessFlags.SkipInstanceMembers | + MemberAccessFlags.SkipTypeBaseClass | + MemberAccessFlags.SkipAttributeAccessOverride + ); + + if (!callInfo) { + return undefined; + } + + const callType = evaluator.getTypeOfMember(callInfo); + if (!isFunction(callType) && !isOverloadedFunction(callType)) { + return undefined; + } + + const boundCallType = evaluator.bindFunctionToClassOrObject( + classType, + callType, + callInfo && isInstantiableClass(callInfo.classType) ? callInfo.classType : undefined, + /* treatConstructorAsClassMethod */ false, + ClassType.cloneAsInstantiable(classType), + /* diag */ undefined, + recursionCount + ); + + if (!boundCallType) { + return undefined; + } + + let useMetaclassCall = false; + + // Look at the signatures of all the __call__ methods to determine whether + // any of them returns something other than the instance of the class being + // constructed. + doForEachSignature(boundCallType, (signature) => { + if (signature.details.declaredReturnType) { + const returnType = FunctionType.getSpecializedReturnType(signature); + if (returnType && shouldSkipNewAndInitEvaluation(evaluator, classType, returnType)) { + useMetaclassCall = true; + } + } + }); + + return useMetaclassCall ? boundCallType : undefined; } function createFunctionFromNewMethod( @@ -820,7 +885,6 @@ function createFunctionFromNewMethod( selfType: ClassType | TypeVarType | undefined, recursionCount: number ): FunctionType | OverloadedFunctionType | undefined { - // Fall back on the __new__ method if __init__ isn't available. const newInfo = lookUpClassMember( classType, '__new__', @@ -829,62 +893,81 @@ function createFunctionFromNewMethod( MemberAccessFlags.SkipObjectBaseClass ); - if (newInfo) { - const newType = evaluator.getTypeOfMember(newInfo); - - const convertNewToConstructor = (newSubtype: FunctionType) => { - let constructorFunction = evaluator.bindFunctionToClassOrObject( - classType, - newSubtype, - newInfo && isInstantiableClass(newInfo.classType) ? newInfo.classType : undefined, - /* treatConstructorAsClassMember */ true, - selfType, - /* diag */ undefined, - recursionCount - ) as FunctionType | undefined; - - if (constructorFunction) { - constructorFunction = FunctionType.clone(constructorFunction); - constructorFunction.details.typeVarScopeId = newSubtype.details.typeVarScopeId; - - if (!constructorFunction.details.docString && classType.details.docString) { - constructorFunction.details.docString = classType.details.docString; - } + if (!newInfo) { + return undefined; + } + + const newType = evaluator.getTypeOfMember(newInfo); - constructorFunction.details.flags &= ~( - FunctionTypeFlags.StaticMethod | FunctionTypeFlags.ConstructorMethod - ); - constructorFunction.details.constructorTypeVarScopeId = getTypeVarScopeId(classType); + const convertNewToConstructor = (newSubtype: FunctionType) => { + // If there are no parameters that include class-scoped type parameters, + // self-specialize the class because the type arguments for the class + // can't be solved if there are no parameters to supply them. + const hasParametersWithTypeVars = newSubtype.details.parameters.some((param, index) => { + if (index === 0 || !param.name) { + return false; } - return constructorFunction; - }; + const paramType = FunctionType.getEffectiveParameterType(newSubtype, index); + const typeVars = getTypeVarArgumentsRecursive(paramType); + return typeVars.some((typeVar) => typeVar.scopeId === getTypeVarScopeId(classType)); + }); - if (isFunction(newType)) { - return convertNewToConstructor(newType); + const boundNew = evaluator.bindFunctionToClassOrObject( + hasParametersWithTypeVars ? selfSpecializeClass(classType) : classType, + newSubtype, + newInfo && isInstantiableClass(newInfo.classType) ? newInfo.classType : undefined, + /* treatConstructorAsClassMethod */ true, + selfType, + /* diag */ undefined, + recursionCount + ) as FunctionType | undefined; + + if (!boundNew) { + return undefined; } - if (isOverloadedFunction(newType)) { - const newOverloads: FunctionType[] = []; - newType.overloads.forEach((overload) => { - const converted = convertNewToConstructor(overload); - if (converted) { - newOverloads.push(converted); - } - }); + const convertedNew = FunctionType.clone(boundNew); + convertedNew.details.typeVarScopeId = newSubtype.details.typeVarScopeId; - if (newOverloads.length === 0) { - return undefined; - } + if (!convertedNew.details.docString && classType.details.docString) { + convertedNew.details.docString = classType.details.docString; + } - if (newOverloads.length === 1) { - return newOverloads[0]; - } + convertedNew.details.flags &= ~(FunctionTypeFlags.StaticMethod | FunctionTypeFlags.ConstructorMethod); + convertedNew.details.constructorTypeVarScopeId = getTypeVarScopeId(classType); + + return convertedNew; + }; + + if (isFunction(newType)) { + return convertNewToConstructor(newType); + } + + if (!isOverloadedFunction(newType)) { + return undefined; + } - return OverloadedFunctionType.create(newOverloads); + const newOverloads: FunctionType[] = []; + newType.overloads.forEach((overload) => { + const converted = convertNewToConstructor(overload); + if (converted) { + newOverloads.push(converted); } + }); + + if (newOverloads.length === 0) { + return undefined; + } + + if (newOverloads.length === 1) { + return newOverloads[0]; } + return OverloadedFunctionType.create(newOverloads); +} + +function createFunctionFromObjectNewMethod(classType: ClassType) { // Return a fallback constructor based on the object.__new__ method. const constructorFunction = FunctionType.createSynthesizedInstance('__new__', FunctionTypeFlags.None); constructorFunction.details.declaredReturnType = ClassType.cloneAsInstance(classType); @@ -917,68 +1000,96 @@ function createFunctionFromInitMethod( MemberAccessFlags.SkipObjectBaseClass ); - if (initInfo) { - const initType = evaluator.getTypeOfMember(initInfo); - const objectType = ClassType.cloneAsInstance(classType); - - function convertInitToConstructor(initSubtype: FunctionType) { - let constructorFunction = evaluator.bindFunctionToClassOrObject( - objectType, - initSubtype, - initInfo && isInstantiableClass(initInfo.classType) ? initInfo.classType : undefined, - /* treatConstructorAsClassMember */ undefined, - selfType, - /* diag */ undefined, - recursionCount - ) as FunctionType | undefined; - - if (constructorFunction) { - constructorFunction = FunctionType.clone(constructorFunction); - constructorFunction.details.declaredReturnType = selfType ?? objectType; - constructorFunction.details.name = ''; - constructorFunction.details.fullName = ''; - - if (constructorFunction.specializedTypes) { - constructorFunction.specializedTypes.returnType = selfType ?? objectType; - } + if (!initInfo) { + return undefined; + } - if (!constructorFunction.details.docString && classType.details.docString) { - constructorFunction.details.docString = classType.details.docString; - } + const initType = evaluator.getTypeOfMember(initInfo); + const objectType = ClassType.cloneAsInstance(classType); + + function convertInitToConstructor(initSubtype: FunctionType) { + const boundInit = evaluator.bindFunctionToClassOrObject( + objectType, + initSubtype, + initInfo && isInstantiableClass(initInfo.classType) ? initInfo.classType : undefined, + /* treatConstructorAsClassMethod */ undefined, + selfType, + /* diag */ undefined, + recursionCount + ) as FunctionType | undefined; + + if (!boundInit) { + return undefined; + } - constructorFunction.details.flags &= ~FunctionTypeFlags.StaticMethod; - constructorFunction.details.constructorTypeVarScopeId = getTypeVarScopeId(classType); - } + const convertedInit = FunctionType.clone(boundInit); + convertedInit.details.declaredReturnType = boundInit.strippedFirstParamType ?? selfType ?? objectType; + convertedInit.details.name = ''; + convertedInit.details.fullName = ''; - return constructorFunction; + if (convertedInit.specializedTypes) { + convertedInit.specializedTypes.returnType = selfType ?? objectType; } - if (isFunction(initType)) { - return convertInitToConstructor(initType); + if (!convertedInit.details.docString && classType.details.docString) { + convertedInit.details.docString = classType.details.docString; } - if (isOverloadedFunction(initType)) { - const initOverloads: FunctionType[] = []; - initType.overloads.forEach((overload) => { - const converted = convertInitToConstructor(overload); - if (converted) { - initOverloads.push(converted); - } - }); + convertedInit.details.flags &= ~FunctionTypeFlags.StaticMethod; + convertedInit.details.constructorTypeVarScopeId = getTypeVarScopeId(classType); - if (initOverloads.length === 0) { - return undefined; - } + return convertedInit; + } - if (initOverloads.length === 1) { - return initOverloads[0]; - } + if (isFunction(initType)) { + return convertInitToConstructor(initType); + } - return OverloadedFunctionType.create(initOverloads); + if (!isOverloadedFunction(initType)) { + return undefined; + } + + const initOverloads: FunctionType[] = []; + initType.overloads.forEach((overload) => { + const converted = convertInitToConstructor(overload); + if (converted) { + initOverloads.push(converted); } + }); + + if (initOverloads.length === 0) { + return undefined; } - return undefined; + if (initOverloads.length === 1) { + return initOverloads[0]; + } + + return OverloadedFunctionType.create(initOverloads); +} + +// If the __call__ method returns a type that is not an instance of the class, +// skip the __new__ and __init__ method evaluation. +function shouldSkipNewAndInitEvaluation( + evaluator: TypeEvaluator, + classType: ClassType, + callMethodReturnType: Type +): boolean { + if ( + !evaluator.assignType(convertToInstance(classType), callMethodReturnType) || + isNever(callMethodReturnType) || + findSubtype(callMethodReturnType, (subtype) => isAny(subtype)) + ) { + return true; + } + + // Handle the special case of an enum class, where the __new__ and __init__ + // methods are replaced at runtime by the metaclass. + if (ClassType.isEnumClass(classType)) { + return true; + } + + return false; } // If __new__ returns a type that is not an instance of the class, skip the @@ -989,7 +1100,7 @@ function shouldSkipInitEvaluation(evaluator: TypeEvaluator, classType: ClassType let skipInitCheck = false; doForEachSubtype(returnType, (subtype) => { - if (isAnyOrUnknown(subtype)) { + if (isUnknown(subtype)) { return; } diff --git a/packages/pyright-internal/src/analyzer/dataClasses.ts b/packages/pyright-internal/src/analyzer/dataClasses.ts index 66efb064eb..bc7cf8fcee 100644 --- a/packages/pyright-internal/src/analyzer/dataClasses.ts +++ b/packages/pyright-internal/src/analyzer/dataClasses.ts @@ -49,6 +49,7 @@ import { isFunction, isInstantiableClass, isOverloadedFunction, + isUnion, OverloadedFunctionType, TupleTypeArgument, Type, @@ -385,6 +386,14 @@ export function synthesizeDataClassMethods( dataClassEntry.hasDefault = true; dataClassEntry.defaultValueExpression = oldEntry.defaultValueExpression; hasDefaultValue = true; + + // Warn the user of this case because it can result in type errors if the + // default value is incompatible with the new type. + evaluator.addDiagnostic( + DiagnosticRule.reportGeneralTypeIssues, + LocMessage.dataClassFieldInheritedDefault().format({ fieldName: variableName }), + variableNameNode + ); } fullDataClassEntries[insertIndex] = dataClassEntry; @@ -832,7 +841,19 @@ function getConverterAsFunction( } if (isInstantiableClass(converterType)) { - return createFunctionFromConstructor(evaluator, converterType); + let fromConstructor = createFunctionFromConstructor(evaluator, converterType); + if (fromConstructor) { + // If conversion to a constructor resulted in a union type, we'll + // choose the first of the two subtypes, which typically corresponds + // to the __init__ method (rather than the __new__ method). + if (isUnion(fromConstructor)) { + fromConstructor = fromConstructor.subtypes[0]; + } + + if (isFunction(fromConstructor) || isOverloadedFunction(fromConstructor)) { + return fromConstructor; + } + } } return undefined; diff --git a/packages/pyright-internal/src/analyzer/importStatementUtils.ts b/packages/pyright-internal/src/analyzer/importStatementUtils.ts index 5c79fc3149..d4dc412bfc 100644 --- a/packages/pyright-internal/src/analyzer/importStatementUtils.ts +++ b/packages/pyright-internal/src/analyzer/importStatementUtils.ts @@ -184,7 +184,9 @@ export function getTextEditsForAutoImportSymbolAddition( importNameInfo = (Array.isArray(importNameInfo) ? importNameInfo : [importNameInfo]).filter( (info) => !!info.name && - !importFrom.imports.some((importAs) => importAs.name.value === info.name && importAs.alias === info.alias) + !importFrom.imports.some( + (importAs) => importAs.name.value === info.name && importAs.alias?.value === info.alias + ) ); if (importNameInfo.length === 0) { diff --git a/packages/pyright-internal/src/analyzer/parseTreeUtils.ts b/packages/pyright-internal/src/analyzer/parseTreeUtils.ts index a388e432c6..c52981215e 100644 --- a/packages/pyright-internal/src/analyzer/parseTreeUtils.ts +++ b/packages/pyright-internal/src/analyzer/parseTreeUtils.ts @@ -2811,3 +2811,31 @@ export function getTypeVarScopesForNode(node: ParseNode): TypeVarScopeId[] { return scopeIds; } + +export function checkDecorator(node: DecoratorNode, value: string): boolean { + return node.expression.nodeType === ParseNodeType.Name && node.expression.value === value; +} + +export function isSimpleDefault(node: ExpressionNode): boolean { + switch (node.nodeType) { + case ParseNodeType.Number: + case ParseNodeType.Constant: + case ParseNodeType.MemberAccess: + return true; + + case ParseNodeType.String: + return (node.token.flags & StringTokenFlags.Format) === 0; + + case ParseNodeType.StringList: + return node.strings.every(isSimpleDefault); + + case ParseNodeType.UnaryOperation: + return isSimpleDefault(node.expression); + + case ParseNodeType.BinaryOperation: + return isSimpleDefault(node.leftExpression) && isSimpleDefault(node.rightExpression); + + default: + return false; + } +} diff --git a/packages/pyright-internal/src/analyzer/properties.ts b/packages/pyright-internal/src/analyzer/properties.ts index 1bcb7b9447..5b2ae9168f 100644 --- a/packages/pyright-internal/src/analyzer/properties.ts +++ b/packages/pyright-internal/src/analyzer/properties.ts @@ -545,7 +545,7 @@ export function assignProperty( destObjectToBind, destAccessType, /* memberClass */ undefined, - /* treatConstructorAsClassMember */ undefined, + /* treatConstructorAsClassMethod */ undefined, /* firstParamType */ undefined, diag?.createAddendum(), recursionCount @@ -555,7 +555,7 @@ export function assignProperty( srcObjectToBind, srcAccessType, /* memberClass */ undefined, - /* treatConstructorAsClassMember */ undefined, + /* treatConstructorAsClassMethod */ undefined, /* firstParamType */ undefined, diag?.createAddendum(), recursionCount diff --git a/packages/pyright-internal/src/analyzer/protocols.ts b/packages/pyright-internal/src/analyzer/protocols.ts index 8dcafc5d36..a417aebc6a 100644 --- a/packages/pyright-internal/src/analyzer/protocols.ts +++ b/packages/pyright-internal/src/analyzer/protocols.ts @@ -15,7 +15,7 @@ import { assignTypeToTypeVar } from './constraintSolver'; import { DeclarationType } from './declaration'; import { assignProperty } from './properties'; import { Symbol } from './symbol'; -import { getLastTypedDeclaredForSymbol, isEffectivelyClassVar } from './symbolUtils'; +import { getLastTypedDeclarationForSymbol, isEffectivelyClassVar } from './symbolUtils'; import { TypeEvaluator } from './typeEvaluatorTypes'; import { ClassType, @@ -447,7 +447,7 @@ function assignClassToProtocolInternal( : ClassType.cloneAsInstance(srcType), srcMemberType, isMemberFromMetaclass ? undefined : (srcMemberInfo.classType as ClassType), - /* treatConstructorAsClassMember */ undefined, + /* treatConstructorAsClassMethod */ undefined, isMemberFromMetaclass ? srcType : selfType, diag?.createAddendum(), recursionCount @@ -493,7 +493,7 @@ function assignClassToProtocolInternal( ClassType.cloneAsInstance(srcType), destMemberType, isMemberFromMetaclass ? undefined : (srcMemberInfo.classType as ClassType), - /* treatConstructorAsClassMember */ undefined, + /* treatConstructorAsClassMethod */ undefined, isMemberFromMetaclass ? srcType : selfType, diag, recursionCount @@ -504,7 +504,7 @@ function assignClassToProtocolInternal( ClassType.cloneAsInstance(destType), destMemberType, destType, - /* treatConstructorAsClassMember */ undefined, + /* treatConstructorAsClassMethod */ undefined, /* firstParamType */ undefined, diag, recursionCount @@ -664,8 +664,8 @@ function assignClassToProtocolInternal( } } - const destPrimaryDecl = getLastTypedDeclaredForSymbol(destSymbol); - const srcPrimaryDecl = getLastTypedDeclaredForSymbol(srcSymbol); + const destPrimaryDecl = getLastTypedDeclarationForSymbol(destSymbol); + const srcPrimaryDecl = getLastTypedDeclarationForSymbol(srcSymbol); if ( destPrimaryDecl?.type === DeclarationType.Variable && diff --git a/packages/pyright-internal/src/analyzer/symbolUtils.ts b/packages/pyright-internal/src/analyzer/symbolUtils.ts index 6a3f87031b..c265eade8d 100644 --- a/packages/pyright-internal/src/analyzer/symbolUtils.ts +++ b/packages/pyright-internal/src/analyzer/symbolUtils.ts @@ -10,7 +10,7 @@ import { Declaration, DeclarationType } from './declaration'; import { Symbol } from './symbol'; -export function getLastTypedDeclaredForSymbol(symbol: Symbol): Declaration | undefined { +export function getLastTypedDeclarationForSymbol(symbol: Symbol): Declaration | undefined { const typedDecls = symbol.getTypedDeclarations(); if (typedDecls.length > 0) { diff --git a/packages/pyright-internal/src/analyzer/typeEvaluator.ts b/packages/pyright-internal/src/analyzer/typeEvaluator.ts index 496d36910c..4504c115b5 100644 --- a/packages/pyright-internal/src/analyzer/typeEvaluator.ts +++ b/packages/pyright-internal/src/analyzer/typeEvaluator.ts @@ -165,7 +165,7 @@ import * as ScopeUtils from './scopeUtils'; import { evaluateStaticBoolExpression } from './staticExpressions'; import { Symbol, SymbolFlags, indeterminateSymbolId } from './symbol'; import { isConstantName, isPrivateName, isPrivateOrProtectedName } from './symbolNameUtils'; -import { getLastTypedDeclaredForSymbol, isEffectivelyClassVar } from './symbolUtils'; +import { getLastTypedDeclarationForSymbol, isEffectivelyClassVar } from './symbolUtils'; import { SpeculativeModeOptions, SpeculativeTypeTracker } from './typeCacheUtils'; import { AbstractSymbol, @@ -4499,7 +4499,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions if (typeParamSymbol) { symbol = typeParamSymbol; assert(symbol.getDeclarations().length === 1); - const decl = getLastTypedDeclaredForSymbol(symbol); + const decl = getLastTypedDeclarationForSymbol(symbol); assert(decl?.type === DeclarationType.TypeParameter); type = getTypeOfTypeParameter(decl.node); setSymbolAccessed(fileInfo, symbol, node); @@ -5330,6 +5330,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions const fileInfo = AnalyzerNodeInfo.getFileInfo(node); let type: Type | undefined; let narrowedTypeForSet: Type | undefined; + let typeErrors = false; let isIncomplete = !!baseTypeResult.isIncomplete; let isAsymmetricAccessor: boolean | undefined; const isRequired = false; @@ -5452,27 +5453,31 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions ); } - if (typeResult && !typeResult.typeErrors) { - type = addConditionToType( - typeResult.type, - getTypeCondition(baseType), - /* skipSelfCondition */ true - ); - - if (typeResult.narrowedTypeForSet) { - narrowedTypeForSet = addConditionToType( - typeResult.narrowedTypeForSet, + if (typeResult) { + if (!typeResult.typeErrors) { + type = addConditionToType( + typeResult.type, getTypeCondition(baseType), /* skipSelfCondition */ true ); + } else { + typeErrors = true; + } + + if (typeResult.isAsymmetricAccessor) { + isAsymmetricAccessor = true; } if (typeResult.isIncomplete) { isIncomplete = true; } - if (typeResult.isAsymmetricAccessor) { - isAsymmetricAccessor = true; + if (typeResult.narrowedTypeForSet) { + narrowedTypeForSet = addConditionToType( + typeResult.narrowedTypeForSet, + getTypeCondition(baseType), + /* skipSelfCondition */ true + ); } if (typeResult.memberAccessDeprecationInfo) { @@ -5625,10 +5630,14 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions isIncomplete = true; } - if (typeResult?.memberAccessDeprecationInfo) { + if (typeResult.memberAccessDeprecationInfo) { memberAccessDeprecationInfo = typeResult.memberAccessDeprecationInfo; } + if (typeResult.typeErrors) { + typeErrors = true; + } + return typeResult.type; }); break; @@ -5725,6 +5734,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions isRequired, isNotRequired, memberAccessDeprecationInfo, + typeErrors, }; } @@ -6012,6 +6022,8 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions ); } + // Do not narrow the type in this case. Assume the declared type. + narrowedTypeForSet = type; isDescriptorError = true; } @@ -9639,7 +9651,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions return undefined; } - const lastDecl = getLastTypedDeclaredForSymbol(symbol); + const lastDecl = getLastTypedDeclarationForSymbol(symbol); if (!lastDecl) { return undefined; } @@ -11563,13 +11575,10 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions } } - // Some typeshed stubs use specialized type annotations in the "self" parameter - // of an overloaded __init__ method to specify which specialized type should - // be constructed. Although this isn't part of the official Python spec, other - // type checkers appear to honor it. + // The type annotation for the "self" parameter in an __init__ method to + // can incluence the type being constructed. if ( type.details.name === '__init__' && - FunctionType.isOverloaded(type) && type.strippedFirstParamType && type.boundToType && isClassInstance(type.strippedFirstParamType) && @@ -12332,7 +12341,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions if (isFunction(concreteParamType) || isOverloadedFunction(concreteParamType)) { if (isInstantiableClass(argType)) { const constructor = createFunctionFromConstructor(evaluatorInterface, argType); - if (constructor && isOverloadedFunction(constructor)) { + if (constructor) { return { isCompatible, argType, @@ -12739,7 +12748,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions if (paramName === 'default') { const expr = argList[i].valueExpression; if (expr) { - const defaultType = getTypeVarTupleDefaultType(expr); + const defaultType = getTypeVarTupleDefaultType(expr, /* isPep695Syntax */ false); if (defaultType) { typeVar.details.defaultType = defaultType; typeVar.details.isDefaultExplicit = true; @@ -12768,10 +12777,11 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions return typeVar; } - function getTypeVarTupleDefaultType(node: ExpressionNode): Type | undefined { + function getTypeVarTupleDefaultType(node: ExpressionNode, isPep695Syntax: boolean): Type | undefined { const argType = getTypeOfExpressionExpectingType(node, { allowUnpackedTuple: true, allowTypeVarsWithoutScopeId: true, + allowForwardReference: isPep695Syntax, }).type; const isUnpackedTuple = isClass(argType) && isTupleClass(argType) && argType.isUnpacked; const isUnpackedTypeVarTuple = isUnpackedVariadicTypeVar(argType); @@ -12818,7 +12828,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions if (paramName === 'default') { const expr = argList[i].valueExpression; if (expr) { - const defaultType = getParamSpecDefaultType(expr); + const defaultType = getParamSpecDefaultType(expr, /* isPep695Syntax */ false); if (defaultType) { paramSpec.details.defaultType = defaultType; paramSpec.details.isDefaultExplicit = true; @@ -12848,7 +12858,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions return paramSpec; } - function getParamSpecDefaultType(node: ExpressionNode): Type | undefined { + function getParamSpecDefaultType(node: ExpressionNode, isPep695Syntax: boolean): Type | undefined { const functionType = FunctionType.createSynthesizedInstance( '', FunctionTypeFlags.SkipArgsKwargsCompatibilityCheck | FunctionTypeFlags.ParamSpecValue @@ -12861,7 +12871,10 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions if (node.nodeType === ParseNodeType.List) { node.entries.forEach((paramExpr, index) => { - const typeResult = getTypeOfExpressionExpectingType(paramExpr, { allowTypeVarsWithoutScopeId: true }); + const typeResult = getTypeOfExpressionExpectingType(paramExpr, { + allowTypeVarsWithoutScopeId: true, + allowForwardReference: isPep695Syntax, + }); FunctionType.addParameter(functionType, { category: ParameterCategory.Simple, @@ -19596,6 +19609,15 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions } else { break; } + } else if (parent.nodeType === ParseNodeType.TypeParameter) { + // If this is a bound or default expression in a type parameter list, + // we need to evaluate it in the context of the type parameter. + if (node === parent.boundExpression || node === parent.defaultExpression) { + getTypeOfTypeParameter(parent); + return; + } + + break; } else { break; } @@ -21254,6 +21276,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions const constraints = node.boundExpression.expressions.map((constraint) => { const constraintType = getTypeOfExpressionExpectingType(constraint, { disallowProtocolAndTypedDict: true, + allowForwardReference: true, }).type; if ( @@ -21280,6 +21303,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions } else { const boundType = getTypeOfExpressionExpectingType(node.boundExpression, { disallowProtocolAndTypedDict: true, + allowForwardReference: true, }).type; if (requiresSpecialization(boundType, { ignorePseudoGeneric: true })) { @@ -21293,7 +21317,9 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions } if (node.typeParamCategory === TypeParameterCategory.ParamSpec) { - const defaultType = node.defaultExpression ? getParamSpecDefaultType(node.defaultExpression) : undefined; + const defaultType = node.defaultExpression + ? getParamSpecDefaultType(node.defaultExpression, /* isPep695Syntax */ true) + : undefined; if (defaultType) { typeVar.details.defaultType = defaultType; @@ -21302,7 +21328,9 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions typeVar.details.defaultType = getUnknownTypeForParamSpec(); } } else if (node.typeParamCategory === TypeParameterCategory.TypeVarTuple) { - const defaultType = node.defaultExpression ? getTypeVarTupleDefaultType(node.defaultExpression) : undefined; + const defaultType = node.defaultExpression + ? getTypeVarTupleDefaultType(node.defaultExpression, /* isPep695Syntax */ true) + : undefined; if (defaultType) { typeVar.details.defaultType = defaultType; @@ -21312,7 +21340,9 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions } } else { const defaultType = node.defaultExpression - ? convertToInstance(getTypeOfExpressionExpectingType(node.defaultExpression).type) + ? convertToInstance( + getTypeOfExpressionExpectingType(node.defaultExpression, { allowForwardReference: true }).type + ) : undefined; if (defaultType) { @@ -24112,6 +24142,20 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions ); if (constructor) { concreteSrcType = constructor; + + // The constructor conversion may result in a union of the + // __init__ and __new__ callables. + if (isUnion(concreteSrcType)) { + return assignType( + destType, + concreteSrcType, + diag, + destTypeVarContext, + srcTypeVarContext, + flags, + recursionCount + ); + } } } @@ -24445,22 +24489,36 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions } else if (remainingDestSubtypes.length === remainingSrcSubtypes.length) { // If the number of remaining source subtypes is the same as the number // of dest TypeVars, try to assign each source subtype to its own dest TypeVar. - remainingDestSubtypes.forEach((destSubtype, index) => { - const srcSubtype = remainingSrcSubtypes[index]; - if ( - !assignType( - destSubtype, - srcSubtype, - diag?.createAddendum(), - destTypeVarContext, - srcTypeVarContext, - flags, - recursionCount - ) - ) { + const reorderedDestSubtypes = [...remainingDestSubtypes]; + + for (let srcIndex = 0; srcIndex < remainingSrcSubtypes.length; srcIndex++) { + let foundMatchForSrc = false; + + for (let destIndex = 0; destIndex < reorderedDestSubtypes.length; destIndex++) { + if ( + assignType( + reorderedDestSubtypes[destIndex], + remainingSrcSubtypes[srcIndex], + diag?.createAddendum(), + destTypeVarContext, + srcTypeVarContext, + flags, + recursionCount + ) + ) { + foundMatchForSrc = true; + // Move the matched dest TypeVar to the end of the list so the other + // dest TypeVars have a better chance of being assigned to. + reorderedDestSubtypes.push(...reorderedDestSubtypes.splice(destIndex, 1)); + break; + } + } + + if (!foundMatchForSrc) { canUseFastPath = false; + break; } - }); + } // We can avoid checking the source subtypes that have already been checked. sortedSrcTypes = remainingSrcSubtypes; @@ -25723,6 +25781,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions remainingFunction.details.typeVarScopeId = effectiveSrcType.details.typeVarScopeId; remainingFunction.details.constructorTypeVarScopeId = effectiveSrcType.details.constructorTypeVarScopeId; + remainingFunction.details.methodClass = effectiveSrcType.details.methodClass; remainingParams.forEach((param) => { FunctionType.addParameter(remainingFunction, param); }); @@ -25785,11 +25844,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions effectiveFlags |= AssignTypeFlags.RetainLiteralsForTypeVar; } - if (isNever(srcReturnType)) { - // We'll allow any function that returns NoReturn to match any - // function return type, consistent with other type checkers. - isReturnTypeCompatible = true; - } else if ( + if ( assignType( destReturnType, srcReturnType, @@ -26752,7 +26807,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions // If the memberType is an instance or class method, creates a new // version of the function that has the "self" or "cls" parameter bound - // to it. If treatConstructorAsClassMember is true, the function is + // to it. If treatConstructorAsClassMethod is true, the function is // treated like a class method even if it's not marked as such. That's // needed to special-case the __new__ magic method when it's invoked as // a constructor (as opposed to by name). @@ -26760,7 +26815,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions baseType: ClassType | undefined, memberType: FunctionType | OverloadedFunctionType, memberClass?: ClassType, - treatConstructorAsClassMember = false, + treatConstructorAsClassMethod = false, selfType?: ClassType | TypeVarType, diag?: DiagnosticAddendum, recursionCount = 0 @@ -26782,6 +26837,13 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions ? baseType : ClassType.cloneAsInstance(specializeClassType(baseType)); + let stripFirstParam = false; + if (isClassInstance(baseType)) { + stripFirstParam = true; + } else if (memberClass && isInstantiableMetaclass(memberClass)) { + stripFirstParam = true; + } + return partiallySpecializeFunctionForBoundClassOrObject( baseType, functionType, @@ -26789,13 +26851,13 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions diag, recursionCount, selfType ?? baseObj, - /* stripFirstParam */ isClassInstance(baseType) + stripFirstParam ); } if ( FunctionType.isClassMethod(functionType) || - (treatConstructorAsClassMember && FunctionType.isConstructorMethod(functionType)) + (treatConstructorAsClassMethod && FunctionType.isConstructorMethod(functionType)) ) { const baseClass = isInstantiableClass(baseType) ? baseType : ClassType.cloneAsInstantiable(baseType); const clsType = selfType ? (convertToInstantiable(selfType) as ClassType | TypeVarType) : undefined; diff --git a/packages/pyright-internal/src/analyzer/typeEvaluatorTypes.ts b/packages/pyright-internal/src/analyzer/typeEvaluatorTypes.ts index 7e096d927f..877600cbb5 100644 --- a/packages/pyright-internal/src/analyzer/typeEvaluatorTypes.ts +++ b/packages/pyright-internal/src/analyzer/typeEvaluatorTypes.ts @@ -610,7 +610,7 @@ export interface TypeEvaluator { baseType: ClassType | undefined, memberType: FunctionType | OverloadedFunctionType, memberClass?: ClassType, - treatConstructorAsClassMember?: boolean, + treatConstructorAsClassMethod?: boolean, selfType?: ClassType | TypeVarType, diag?: DiagnosticAddendum, recursionCount?: number diff --git a/packages/pyright-internal/src/analyzer/typeGuards.ts b/packages/pyright-internal/src/analyzer/typeGuards.ts index 75b5e27fad..8dded6f95c 100644 --- a/packages/pyright-internal/src/analyzer/typeGuards.ts +++ b/packages/pyright-internal/src/analyzer/typeGuards.ts @@ -132,6 +132,12 @@ export function getTypeNarrowingCallback( testExpression.operator === OperatorType.Is || testExpression.operator === OperatorType.IsNot; const equalsOrNotEqualsOperator = testExpression.operator === OperatorType.Equals || testExpression.operator === OperatorType.NotEquals; + const comparisonOperator = + equalsOrNotEqualsOperator || + testExpression.operator === OperatorType.LessThan || + testExpression.operator === OperatorType.LessThanOrEqual || + testExpression.operator === OperatorType.GreaterThan || + testExpression.operator === OperatorType.GreaterThanOrEqual; if (isOrIsNotOperator || equalsOrNotEqualsOperator) { // Invert the "isPositiveTest" value if this is an "is not" operation. @@ -412,43 +418,6 @@ export function getTypeNarrowingCallback( } } - // Look for len(x) == or len(x) != - if ( - equalsOrNotEqualsOperator && - testExpression.leftExpression.nodeType === ParseNodeType.Call && - testExpression.leftExpression.arguments.length === 1 - ) { - const arg0Expr = testExpression.leftExpression.arguments[0].valueExpression; - - if (ParseTreeUtils.isMatchingExpression(reference, arg0Expr)) { - const callTypeResult = evaluator.getTypeOfExpression( - testExpression.leftExpression.leftExpression, - EvaluatorFlags.CallBaseDefaults - ); - const callType = callTypeResult.type; - - if (isFunction(callType) && callType.details.fullName === 'builtins.len') { - const rightTypeResult = evaluator.getTypeOfExpression(testExpression.rightExpression); - const rightType = rightTypeResult.type; - - if ( - isClassInstance(rightType) && - typeof rightType.literalValue === 'number' && - rightType.literalValue >= 0 - ) { - const tupleLength = rightType.literalValue; - - return (type: Type) => { - return { - type: narrowTypeForTupleLength(evaluator, type, tupleLength, adjIsPositiveTest), - isIncomplete: !!callTypeResult.isIncomplete || !!rightTypeResult.isIncomplete, - }; - }; - } - } - } - } - // Look for X.Y == or X.Y != if ( equalsOrNotEqualsOperator && @@ -530,6 +499,70 @@ export function getTypeNarrowingCallback( } } + // Look for len(x) == , len(x) != , len(x) < , etc. + if ( + comparisonOperator && + testExpression.leftExpression.nodeType === ParseNodeType.Call && + testExpression.leftExpression.arguments.length === 1 + ) { + const arg0Expr = testExpression.leftExpression.arguments[0].valueExpression; + + if (ParseTreeUtils.isMatchingExpression(reference, arg0Expr)) { + const callTypeResult = evaluator.getTypeOfExpression( + testExpression.leftExpression.leftExpression, + EvaluatorFlags.CallBaseDefaults + ); + const callType = callTypeResult.type; + + if (isFunction(callType) && callType.details.fullName === 'builtins.len') { + const rightTypeResult = evaluator.getTypeOfExpression(testExpression.rightExpression); + const rightType = rightTypeResult.type; + + if ( + isClassInstance(rightType) && + typeof rightType.literalValue === 'number' && + rightType.literalValue >= 0 + ) { + let tupleLength = rightType.literalValue; + + // We'll treat <, <= and == as positive tests with >=, > and != as + // their negative counterparts. + const isLessOrEqual = + testExpression.operator === OperatorType.Equals || + testExpression.operator === OperatorType.LessThan || + testExpression.operator === OperatorType.LessThanOrEqual; + + const adjIsPositiveTest = isLessOrEqual ? isPositiveTest : !isPositiveTest; + + // For <= (or its negative counterpart >), adjust the tuple length by 1. + if ( + testExpression.operator === OperatorType.LessThanOrEqual || + testExpression.operator === OperatorType.GreaterThan + ) { + tupleLength++; + } + + const isEqualityCheck = + testExpression.operator === OperatorType.Equals || + testExpression.operator === OperatorType.NotEquals; + + return (type: Type) => { + return { + type: narrowTypeForTupleLength( + evaluator, + type, + tupleLength, + adjIsPositiveTest, + !isEqualityCheck + ), + isIncomplete: !!callTypeResult.isIncomplete || !!rightTypeResult.isIncomplete, + }; + }; + } + } + } + } + if (testExpression.operator === OperatorType.In || testExpression.operator === OperatorType.NotIn) { // Look for "x in y" or "x not in y" where y is one of several built-in types. if (ParseTreeUtils.isMatchingExpression(reference, testExpression.leftExpression)) { @@ -1897,7 +1930,8 @@ function narrowTypeForTupleLength( evaluator: TypeEvaluator, referenceType: Type, lengthValue: number, - isPositiveTest: boolean + isPositiveTest: boolean, + isLessThanCheck: boolean ) { return mapSubtypes(referenceType, (subtype) => { const concreteSubtype = evaluator.makeTopLevelTypeVarsConcrete(subtype); @@ -1918,7 +1952,10 @@ function narrowTypeForTupleLength( // If the tuple contains no unbounded elements, then we know its length exactly. if (!concreteSubtype.tupleTypeArguments.some((typeArg) => typeArg.isUnbounded)) { - const tupleLengthMatches = concreteSubtype.tupleTypeArguments.length === lengthValue; + const tupleLengthMatches = isLessThanCheck + ? concreteSubtype.tupleTypeArguments.length < lengthValue + : concreteSubtype.tupleTypeArguments.length === lengthValue; + return tupleLengthMatches === isPositiveTest ? subtype : undefined; } @@ -1926,31 +1963,68 @@ function narrowTypeForTupleLength( // necessary to match the lengthValue. const elementsToAdd = lengthValue - concreteSubtype.tupleTypeArguments.length + 1; - // If the specified length is smaller than the minimum length of this tuple, - // we can rule it out for a positive test. - if (elementsToAdd < 0) { - return isPositiveTest ? undefined : subtype; + if (!isLessThanCheck) { + // If the specified length is smaller than the minimum length of this tuple, + // we can rule it out for a positive test and rule it in for a negative test. + if (elementsToAdd < 0) { + return isPositiveTest ? undefined : subtype; + } + + if (!isPositiveTest) { + return subtype; + } + + return expandUnboundedTupleElement(concreteSubtype, elementsToAdd, /* keepUnbounded */ false); } - if (!isPositiveTest) { + // Place an upper limit on the number of union subtypes we + // will expand the tuple to. + const maxTupleUnionExpansion = 32; + if (elementsToAdd > maxTupleUnionExpansion) { return subtype; } - const tupleTypeArgs: TupleTypeArgument[] = []; - concreteSubtype.tupleTypeArguments.forEach((typeArg) => { - if (!typeArg.isUnbounded) { - tupleTypeArgs.push(typeArg); - } else { - for (let i = 0; i < elementsToAdd; i++) { - tupleTypeArgs.push({ isUnbounded: false, type: typeArg.type }); - } + if (isPositiveTest) { + if (elementsToAdd < 1) { + return undefined; } - }); - return specializeTupleClass(concreteSubtype, tupleTypeArgs); + const typesToCombine: Type[] = []; + + for (let i = 0; i < elementsToAdd; i++) { + typesToCombine.push(expandUnboundedTupleElement(concreteSubtype, i, /* keepUnbounded */ false)); + } + + return combineTypes(typesToCombine); + } + + return expandUnboundedTupleElement(concreteSubtype, elementsToAdd, /* keepUnbounded */ true); }); } +// Expands a tuple type that contains an unbounded element to include +// multiple bounded elements of that same type in place of (or in addition +// to) the unbounded element. +function expandUnboundedTupleElement(tupleType: ClassType, elementsToAdd: number, keepUnbounded: boolean) { + const tupleTypeArgs: TupleTypeArgument[] = []; + + tupleType.tupleTypeArguments!.forEach((typeArg) => { + if (!typeArg.isUnbounded) { + tupleTypeArgs.push(typeArg); + } else { + for (let i = 0; i < elementsToAdd; i++) { + tupleTypeArgs.push({ isUnbounded: false, type: typeArg.type }); + } + + if (keepUnbounded) { + tupleTypeArgs.push(typeArg); + } + } + }); + + return specializeTupleClass(tupleType, tupleTypeArgs); +} + // Attempts to narrow a type (make it more constrained) based on an "in" binary operator. function narrowTypeForContainerType( evaluator: TypeEvaluator, @@ -2046,67 +2120,71 @@ export function narrowTypeForContainerElementType(evaluator: TypeEvaluator, refe // supertypes of the element types. For example, if the element type // is "int | str" and the reference type is "float | bytes", we can // narrow the reference type to "float" because it is a supertype of "int". - const narrowedSupertypes = mapSubtypes(referenceType, (referenceSubtype) => { - const concreteReferenceType = evaluator.makeTopLevelTypeVarsConcrete(referenceSubtype); + const narrowedSupertypes = evaluator.mapSubtypesExpandTypeVars( + referenceType, + /* options */ undefined, + (referenceSubtype) => { + if (isAnyOrUnknown(referenceSubtype)) { + canNarrow = false; + return referenceSubtype; + } - if (isAnyOrUnknown(concreteReferenceType)) { - canNarrow = false; - return referenceSubtype; - } + // Handle "type" specially. + if (isClassInstance(referenceSubtype) && ClassType.isBuiltIn(referenceSubtype, 'type')) { + canNarrow = false; + return referenceSubtype; + } - // Handle "type" specially. - if (isClassInstance(concreteReferenceType) && ClassType.isBuiltIn(concreteReferenceType, 'type')) { - canNarrow = false; - return referenceSubtype; - } + if (evaluator.assignType(elementType, referenceSubtype)) { + return referenceSubtype; + } - if (evaluator.assignType(elementType, concreteReferenceType)) { - return referenceSubtype; - } + if (evaluator.assignType(elementTypeWithoutLiteral, referenceSubtype)) { + return mapSubtypes(elementType, (elementSubtype) => { + if ( + isClassInstance(elementSubtype) && + isSameWithoutLiteralValue(referenceSubtype, elementSubtype) + ) { + return elementSubtype; + } + return undefined; + }); + } - if (evaluator.assignType(elementTypeWithoutLiteral, concreteReferenceType)) { - return mapSubtypes(elementType, (elementSubtype) => { - if ( - isClassInstance(elementSubtype) && - isSameWithoutLiteralValue(concreteReferenceType, elementSubtype) - ) { - return elementSubtype; - } - return undefined; - }); + return undefined; } - - return undefined; - }); + ); // Look for cases where one or more of the reference subtypes are // subtypes of the element types. For example, if the element type // is "int | str" and the reference type is "object", we can // narrow the reference type to "int | str" because they are both // subtypes of "object". - const narrowedSubtypes = mapSubtypes(elementType, (elementSubtype) => { - const concreteElementType = evaluator.makeTopLevelTypeVarsConcrete(elementSubtype); + const narrowedSubtypes = evaluator.mapSubtypesExpandTypeVars( + elementType, + /* options */ undefined, + (elementSubtype) => { + if (isAnyOrUnknown(elementSubtype)) { + canNarrow = false; + return referenceType; + } - if (isAnyOrUnknown(concreteElementType)) { - canNarrow = false; - return referenceType; - } + // Handle the special case where the reference type is a dict or Mapping and + // the element type is a TypedDict. In this case, we can't say whether there + // is a type overlap, so don't apply narrowing. + if (isClassInstance(referenceType) && ClassType.isBuiltIn(referenceType, ['dict', 'Mapping'])) { + if (isClassInstance(elementSubtype) && ClassType.isTypedDictClass(elementSubtype)) { + return elementSubtype; + } + } - // Handle the special case where the reference type is a dict or Mapping and - // the element type is a TypedDict. In this case, we can't say whether there - // is a type overlap, so don't apply narrowing. - if (isClassInstance(referenceType) && ClassType.isBuiltIn(referenceType, ['dict', 'Mapping'])) { - if (isClassInstance(concreteElementType) && ClassType.isTypedDictClass(concreteElementType)) { - return concreteElementType; + if (evaluator.assignType(referenceType, elementSubtype)) { + return elementSubtype; } - } - if (evaluator.assignType(referenceType, concreteElementType)) { - return concreteElementType; + return undefined; } - - return undefined; - }); + ); return canNarrow ? combineTypes([narrowedSupertypes, narrowedSubtypes]) : referenceType; } @@ -2119,7 +2197,7 @@ function narrowTypeForTypedDictKey( literalKey: ClassType, isPositiveTest: boolean ): Type { - const narrowedType = mapSubtypes(referenceType, (subtype) => { + const narrowedType = evaluator.mapSubtypesExpandTypeVars(referenceType, /* options */ undefined, (subtype) => { if (isClassInstance(subtype) && ClassType.isTypedDictClass(subtype)) { const entries = getTypedDictMembersForClass(evaluator, subtype, /* allowNarrowed */ true); const tdEntry = entries.knownItems.get(literalKey.literalValue as string) ?? entries.extraItems; diff --git a/packages/pyright-internal/src/analyzer/typeUtils.ts b/packages/pyright-internal/src/analyzer/typeUtils.ts index f9d9d501d9..05f935d29f 100644 --- a/packages/pyright-internal/src/analyzer/typeUtils.ts +++ b/packages/pyright-internal/src/analyzer/typeUtils.ts @@ -4267,21 +4267,21 @@ class ApplySolvedTypeVarsTransformer extends TypeVarTransformer { // it represents an instance of a type. If the replacement includes // a generic class that has not been specialized, specialize it // now with default type arguments. - if (this._options.unknownIfNotFound) { - replacement = mapSubtypes(replacement, (subtype) => { - if (isClassInstance(subtype)) { - // If the includeSubclasses wasn't set, force it to be set by - // converting to/from an instantiable. - if (!subtype.includeSubclasses) { - subtype = ClassType.cloneAsInstance(ClassType.cloneAsInstantiable(subtype)); - } + replacement = mapSubtypes(replacement, (subtype) => { + if (isClassInstance(subtype)) { + // If the includeSubclasses wasn't set, force it to be set by + // converting to/from an instantiable. + if (!subtype.includeSubclasses) { + subtype = ClassType.cloneAsInstance(ClassType.cloneAsInstantiable(subtype)); + } + if (this._options.unknownIfNotFound) { return specializeWithDefaultTypeArgs(subtype); } + } - return subtype; - }); - } + return subtype; + }); } if (isTypeVar(replacement) && typeVar.isVariadicUnpacked && replacement.details.isVariadic) { diff --git a/packages/pyright-internal/src/analyzer/typedDicts.ts b/packages/pyright-internal/src/analyzer/typedDicts.ts index 6898eafcfb..e4bcaae215 100644 --- a/packages/pyright-internal/src/analyzer/typedDicts.ts +++ b/packages/pyright-internal/src/analyzer/typedDicts.ts @@ -29,7 +29,7 @@ import * as AnalyzerNodeInfo from './analyzerNodeInfo'; import { DeclarationType, VariableDeclaration } from './declaration'; import * as ParseTreeUtils from './parseTreeUtils'; import { Symbol, SymbolFlags, SymbolTable } from './symbol'; -import { getLastTypedDeclaredForSymbol } from './symbolUtils'; +import { getLastTypedDeclarationForSymbol } from './symbolUtils'; import { EvaluatorUsage, FunctionArgument, TypeEvaluator, TypeResult, TypeResultWithNode } from './typeEvaluatorTypes'; import { AnyType, @@ -996,7 +996,7 @@ function getTypedDictMembersForClassRecursive( ClassType.getSymbolTable(classType).forEach((symbol, name) => { if (!symbol.isIgnoredForProtocolMatch()) { // Only variables (not functions, classes, etc.) are considered. - const lastDecl = getLastTypedDeclaredForSymbol(symbol); + const lastDecl = getLastTypedDeclarationForSymbol(symbol); if (lastDecl && lastDecl.type === DeclarationType.Variable) { let valueType = evaluator.getEffectiveTypeOfSymbol(symbol); diff --git a/packages/pyright-internal/src/analyzer/types.ts b/packages/pyright-internal/src/analyzer/types.ts index 32cdce5918..dfee1424c9 100644 --- a/packages/pyright-internal/src/analyzer/types.ts +++ b/packages/pyright-internal/src/analyzer/types.ts @@ -1821,6 +1821,7 @@ export namespace FunctionType { FunctionType.addHigherOrderTypeVarScopeIds(newFunction, paramSpecValue.details.higherOrderTypeVarScopeIds); newFunction.details.paramSpec = paramSpecValue.details.paramSpec; + newFunction.details.methodClass = paramSpecValue.details.methodClass; } return newFunction; diff --git a/packages/pyright-internal/src/backgroundAnalysisBase.ts b/packages/pyright-internal/src/backgroundAnalysisBase.ts index e2de1882f9..e951791398 100644 --- a/packages/pyright-internal/src/backgroundAnalysisBase.ts +++ b/packages/pyright-internal/src/backgroundAnalysisBase.ts @@ -569,7 +569,9 @@ export abstract class BackgroundAnalysisRunnerBase extends BackgroundThreadBase } protected handleEnsurePartialStubPackages(executionRoot: string | undefined) { - const execEnv = this._configOptions.getExecutionEnvironments().find((e) => e.root === executionRoot); + const execEnv = this._configOptions + .getExecutionEnvironments() + .find((e) => e.root?.toString() === executionRoot); if (execEnv) { this.importResolver.ensurePartialStubPackages(execEnv); } diff --git a/packages/pyright-internal/src/backgroundThreadBase.ts b/packages/pyright-internal/src/backgroundThreadBase.ts index e056137fd9..5352ae4db2 100644 --- a/packages/pyright-internal/src/backgroundThreadBase.ts +++ b/packages/pyright-internal/src/backgroundThreadBase.ts @@ -108,7 +108,7 @@ export class BackgroundThreadBase { // Function used to serialize specific types that can't automatically be serialized. // Exposed here so it can be reused by a caller that wants to add more cases. -export function serializeReplacer(key: string, value: any) { +export function serializeReplacer(value: any) { if (Uri.is(value) && value.toJsonObj !== undefined) { return { __serialized_uri_val: value.toJsonObj() }; } @@ -134,10 +134,10 @@ export function serializeReplacer(key: string, value: any) { export function serialize(obj: any): string { // Convert the object to a string so it can be sent across a message port. - return JSON.stringify(obj, serializeReplacer); + return JSON.stringify(obj, (k, v) => serializeReplacer(v)); } -export function deserializeReviver(key: string, value: any) { +export function deserializeReviver(value: any) { if (value && typeof value === 'object') { if (value.__serialized_uri_val !== undefined) { return Uri.fromJsonObj(value.__serialized_uri_val); @@ -168,7 +168,7 @@ export function deserialize(json: string | null): T { return undefined as any; } // Convert the string back to an object. - return JSON.parse(json, deserializeReviver); + return JSON.parse(json, (k, v) => deserializeReviver(v)); } export interface MessagePoster { @@ -176,13 +176,9 @@ export interface MessagePoster { } export function run(code: () => Promise, port: MessagePoster): Promise; -export function run( - code: () => Promise, - port: MessagePoster, - serializer: (obj: any) => string -): Promise; +export function run(code: () => Promise, port: MessagePoster, serializer: (obj: any) => any): Promise; export function run(code: () => T, port: MessagePoster): void; -export function run(code: () => T, port: MessagePoster, serializer: (obj: any) => string): void; +export function run(code: () => T, port: MessagePoster, serializer: (obj: any) => any): void; export function run( code: () => T | Promise, port: MessagePoster, @@ -218,7 +214,7 @@ export function run( } } -export function getBackgroundWaiter(port: MessagePort, deserializer = deserialize): Promise { +export function getBackgroundWaiter(port: MessagePort, deserializer: (v: any) => T = deserialize): Promise { return new Promise((resolve, reject) => { port.on('message', (m: RequestResponse) => { switch (m.kind) { diff --git a/packages/pyright-internal/src/languageService/completionProvider.ts b/packages/pyright-internal/src/languageService/completionProvider.ts index feb6884b79..cff22f10a9 100644 --- a/packages/pyright-internal/src/languageService/completionProvider.ts +++ b/packages/pyright-internal/src/languageService/completionProvider.ts @@ -39,7 +39,7 @@ import { getScopeForNode } from '../analyzer/scopeUtils'; import { isStubFile, SourceMapper } from '../analyzer/sourceMapper'; import { Symbol, SymbolTable } from '../analyzer/symbol'; import * as SymbolNameUtils from '../analyzer/symbolNameUtils'; -import { getLastTypedDeclaredForSymbol, isVisibleExternally } from '../analyzer/symbolUtils'; +import { getLastTypedDeclarationForSymbol, isVisibleExternally } from '../analyzer/symbolUtils'; import { getTypedDictMembersForClass } from '../analyzer/typedDicts'; import { getModuleDocStringFromUris } from '../analyzer/typeDocStringUtils'; import { CallSignatureInfo, TypeEvaluator } from '../analyzer/typeEvaluatorTypes'; @@ -405,30 +405,6 @@ export class CompletionProvider { return this.program.configOptions; } - protected isSimpleDefault(node: ExpressionNode): boolean { - switch (node.nodeType) { - case ParseNodeType.Number: - case ParseNodeType.Constant: - case ParseNodeType.MemberAccess: - return true; - - case ParseNodeType.String: - return (node.token.flags & StringTokenFlags.Format) === 0; - - case ParseNodeType.StringList: - return node.strings.every(this.isSimpleDefault); - - case ParseNodeType.UnaryOperation: - return this.isSimpleDefault(node.expression); - - case ParseNodeType.BinaryOperation: - return this.isSimpleDefault(node.leftExpression) && this.isSimpleDefault(node.rightExpression); - - default: - return false; - } - } - protected getMethodOverrideCompletions( priorWord: string, partialName: NameNode, @@ -452,13 +428,13 @@ export class CompletionProvider { } } - const staticmethod = decorators?.some((d) => this.checkDecorator(d, 'staticmethod')) ?? false; - const classmethod = decorators?.some((d) => this.checkDecorator(d, 'classmethod')) ?? false; + const staticmethod = decorators?.some((d) => ParseTreeUtils.checkDecorator(d, 'staticmethod')) ?? false; + const classmethod = decorators?.some((d) => ParseTreeUtils.checkDecorator(d, 'classmethod')) ?? false; const completionMap = new CompletionMap(); symbolTable.forEach((symbol, name) => { - let decl = getLastTypedDeclaredForSymbol(symbol); + let decl = getLastTypedDeclarationForSymbol(symbol); if (decl && decl.type === DeclarationType.Function) { if (StringUtils.isPatternInSymbol(partialName.value, name)) { const declaredType = this.evaluator.getTypeForDeclaration(decl)?.type; @@ -636,7 +612,7 @@ export class CompletionProvider { // Make sure we don't crash due to OOM. this.program.handleMemoryHighUsage(); - let primaryDecl = getLastTypedDeclaredForSymbol(symbol); + let primaryDecl = getLastTypedDeclarationForSymbol(symbol); if (!primaryDecl) { const declarations = symbol.getDeclarations(); if (declarations.length > 0) { @@ -893,10 +869,6 @@ export class CompletionProvider { } } - protected checkDecorator(node: DecoratorNode, value: string): boolean { - return node.expression.nodeType === ParseNodeType.Name && node.expression.value === value; - } - protected addExtraCommitChar(item: CompletionItem) { // extra commit char is not supported. } @@ -1618,7 +1590,7 @@ export class CompletionProvider { } private _isOverload(node: DecoratorNode): boolean { - return this.checkDecorator(node, 'overload'); + return ParseTreeUtils.checkDecorator(node, 'overload'); } private _createSingleKeywordCompletion(keyword: string): CompletionMap { @@ -1789,7 +1761,7 @@ export class CompletionProvider { const enclosingFunc = ParseTreeUtils.getEnclosingFunction(partialName); symbolTable.forEach((symbol, name) => { - const decl = getLastTypedDeclaredForSymbol(symbol); + const decl = getLastTypedDeclarationForSymbol(symbol); if (!decl || decl.type !== DeclarationType.Function) { return; } @@ -1885,7 +1857,7 @@ export class CompletionProvider { if (param.defaultValue) { paramString += paramTypeAnnotation ? ' = ' : '='; - const useEllipsis = ellipsisForDefault ?? !this.isSimpleDefault(param.defaultValue); + const useEllipsis = ellipsisForDefault ?? !ParseTreeUtils.isSimpleDefault(param.defaultValue); paramString += useEllipsis ? '...' : ParseTreeUtils.printExpression(param.defaultValue, printFlags); } diff --git a/packages/pyright-internal/src/languageService/symbolIndexer.ts b/packages/pyright-internal/src/languageService/symbolIndexer.ts index 3c69e3a038..a06674af36 100644 --- a/packages/pyright-internal/src/languageService/symbolIndexer.ts +++ b/packages/pyright-internal/src/languageService/symbolIndexer.ts @@ -11,7 +11,7 @@ import { CancellationToken, CompletionItemKind, SymbolKind } from 'vscode-langua import { AnalyzerFileInfo } from '../analyzer/analyzerFileInfo'; import * as AnalyzerNodeInfo from '../analyzer/analyzerNodeInfo'; import { AliasDeclaration, Declaration, DeclarationType } from '../analyzer/declaration'; -import { getLastTypedDeclaredForSymbol, isVisibleExternally } from '../analyzer/symbolUtils'; +import { getLastTypedDeclarationForSymbol, isVisibleExternally } from '../analyzer/symbolUtils'; import { throwIfCancellationRequested } from '../common/cancellationUtils'; import { getSymbolKind } from '../common/lspUtils'; import { convertOffsetsToRange, convertTextRangeToRange } from '../common/positionUtils'; @@ -93,7 +93,7 @@ function collectSymbolIndexData( } // Prefer declarations with a defined type. - let declaration = getLastTypedDeclaredForSymbol(symbol); + let declaration = getLastTypedDeclarationForSymbol(symbol); // Fall back to declarations without a type. if (!declaration && symbol.hasDeclarations()) { diff --git a/packages/pyright-internal/src/languageService/tooltipUtils.ts b/packages/pyright-internal/src/languageService/tooltipUtils.ts index 133edda369..ae3cf42b94 100644 --- a/packages/pyright-internal/src/languageService/tooltipUtils.ts +++ b/packages/pyright-internal/src/languageService/tooltipUtils.ts @@ -442,13 +442,13 @@ export function getClassAndConstructorTypes(node: NameNode, evaluator: TypeEvalu // Prefer `__new__` if it doesn't have default params (*args: Any, **kwargs: Any) or no params (). if (isFunction(newMemberType) || isOverloadedFunction(newMemberType)) { - // Set `treatConstructorAsClassMember` to true to exclude `cls` as a parameter. + // Set `treatConstructorAsClassMethod` to true to exclude `cls` as a parameter. methodType = bindFunctionToClassOrObjectToolTip( evaluator, node, instanceType, newMemberType, - /* treatConstructorAsClassMember */ true + /* treatConstructorAsClassMethod */ true ); } } @@ -462,13 +462,13 @@ export function bindFunctionToClassOrObjectToolTip( node: ExpressionNode, baseType: ClassType | undefined, memberType: FunctionType | OverloadedFunctionType, - treatConstructorAsClassMember?: boolean + treatConstructorAsClassMethod?: boolean ): FunctionType | OverloadedFunctionType | undefined { const methodType = evaluator.bindFunctionToClassOrObject( baseType, memberType, /* memberClass */ undefined, - treatConstructorAsClassMember + treatConstructorAsClassMethod ); if (!methodType) { diff --git a/packages/pyright-internal/src/localization/localize.ts b/packages/pyright-internal/src/localization/localize.ts index c69ef70def..1de187be9a 100644 --- a/packages/pyright-internal/src/localization/localize.ts +++ b/packages/pyright-internal/src/localization/localize.ts @@ -354,6 +354,8 @@ export namespace Localizer { new ParameterizedString<{ funcName: string; fieldType: string; fieldName: string }>( getRawString('Diagnostic.dataClassConverterOverloads') ); + export const dataClassFieldInheritedDefault = () => + new ParameterizedString<{ fieldName: string }>(getRawString('Diagnostic.dataClassFieldInheritedDefault')); export const dataClassFieldWithDefault = () => getRawString('Diagnostic.dataClassFieldWithDefault'); export const dataClassFieldWithoutAnnotation = () => getRawString('Diagnostic.dataClassFieldWithoutAnnotation'); export const dataClassFieldWithPrivateName = () => getRawString('Diagnostic.dataClassFieldWithPrivateName'); @@ -563,6 +565,7 @@ export namespace Localizer { ); export const inconsistentIndent = () => getRawString('Diagnostic.inconsistentIndent'); export const inconsistentTabs = () => getRawString('Diagnostic.inconsistentTabs'); + export const initMethodSelfParamTypeVar = () => getRawString('Diagnostic.initMethodSelfParamTypeVar'); export const initMustReturnNone = () => getRawString('Diagnostic.initMustReturnNone'); export const initSubclassClsParam = () => getRawString('Diagnostic.initSubclassClsParam'); export const initSubclassCallFailed = () => getRawString('Diagnostic.initSubclassCallFailed'); diff --git a/packages/pyright-internal/src/localization/package.nls.cs.json b/packages/pyright-internal/src/localization/package.nls.cs.json index edd5576c6c..7faa870b39 100644 --- a/packages/pyright-internal/src/localization/package.nls.cs.json +++ b/packages/pyright-internal/src/localization/package.nls.cs.json @@ -784,6 +784,7 @@ "typedDictFieldTypeMismatch": "Typ {type} se nedá přiřadit k položce {name}", "typedDictFieldUndefined": "{name} je nedefinovaná položka v typu {type}", "typedDictFinalMismatch": "{sourceType} není kompatibilní s {destType} z důvodu neshody @final", + "typedDictKeyAccess": "Použít [\"{name}\"] k odkazování na položku v TypedDict", "typedDictNotAllowed": "TypedDict se nedá použít pro kontroly instancí nebo tříd.", "unhashableType": "Typ „{type}“ nejde zatřiďovat", "uninitializedAbstractVariable": "Proměnná instance {name} je definovaná v abstraktní základní třídě {classType}, ale neinicializovala se", diff --git a/packages/pyright-internal/src/localization/package.nls.de.json b/packages/pyright-internal/src/localization/package.nls.de.json index 960fd4e850..510d2c372a 100644 --- a/packages/pyright-internal/src/localization/package.nls.de.json +++ b/packages/pyright-internal/src/localization/package.nls.de.json @@ -580,7 +580,7 @@ "unnecessaryIsInstanceAlways": "Nicht erforderlicher isinstance-Aufruf; \"{testType}\" ist immer eine Instanz von \"{classType}\"", "unnecessaryIsSubclassAlways": "Nicht erforderlicher issubclass-Aufruf; \"{testType}\" ist immer eine Unterklasse von \"{classType}\"", "unnecessaryPyrightIgnore": "Unnötiger \"# pyright: ignore\"-Kommentar", - "unnecessaryPyrightIgnoreRule": "Unnötiger \"# pyright: ignore\"-Kommentar", + "unnecessaryPyrightIgnoreRule": "Unnötiger \"# pyright: ignore\"-Regel: \"{name}\"", "unnecessaryTypeIgnore": "Nicht erforderlicher \"# type: ignore\"-Kommentar", "unpackArgCount": "Nach \"Required\" wurde ein einzelnes Typargument erwartet.", "unpackExpectedTypeVarTuple": "„TypeVarTuple“ oder „Tupel“ als Typargument für „Unpack“ erwartet", @@ -784,6 +784,7 @@ "typedDictFieldTypeMismatch": "Der Typ „{type}“ kann dem Element „{name}“ nicht zugewiesen werden.", "typedDictFieldUndefined": "„{name}“ ist ein nicht definiertes Element im Typ „{type}“.", "typedDictFinalMismatch": "\"{sourceType}\" ist aufgrund eines @final-Konflikts nicht mit \"{destType}\" kompatibel.", + "typedDictKeyAccess": "[\"{name}\"] verwenden, um in TypedDict auf ein Element zu verweisen", "typedDictNotAllowed": "TypedDict kann nicht für Instanzen- oder Klassenüberprüfungen verwendet werden.", "unhashableType": "Der Typ \"{type}\" kann nicht mit einem Hash erstellt werden.", "uninitializedAbstractVariable": "Die Instanzvariable \"{name}\" ist in einer abstrakten Basisklasse \"{classType}\" definiert, aber nicht initialisiert.", 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 1b3fed0321..ec43156e75 100644 --- a/packages/pyright-internal/src/localization/package.nls.en-us.json +++ b/packages/pyright-internal/src/localization/package.nls.en-us.json @@ -92,6 +92,7 @@ "dataClassBaseClassNotFrozen": "A frozen class cannot inherit from a class that is not frozen", "dataClassConverterFunction": "Argument of type \"{argType}\" is not a valid converter for field \"{fieldName}\" of type \"{fieldType}\"", "dataClassConverterOverloads": "No overloads of \"{funcName}\" are valid converters for field \"{fieldName}\" of type \"{fieldType}\"", + "dataClassFieldInheritedDefault": "\"{fieldName}\" overrides a field of the same name but is missing a default value", "dataClassFieldWithDefault": "Fields without default values cannot appear after fields with default values", "dataClassFieldWithoutAnnotation": "Dataclass field without type annotation will cause runtime exception", "dataClassFieldWithPrivateName": "Dataclass field cannot use private name", @@ -177,7 +178,7 @@ "expectedIn": "Expected \"in\"", "expectedFunctionAfterAsync": "Expected function definition after \"async\"", "expectedFunctionName": "Expected function name after \"def\"", - "expectedMemberName": "Expected member name after \".\"", + "expectedMemberName": "Expected attribute name after \".\"", "expectedModuleName": "Expected module name", "expectedNameAfterAs": "Expected symbol name after \"as\"", "expectedNamedParameter": "Keyword parameter must follow \"*\"", @@ -242,6 +243,7 @@ "inconsistentIndent": "Unindent amount does not match previous indent", "initMustReturnNone": "Return type of \"__init__\" must be None", "inconsistentTabs": "Inconsistent use of tabs and spaces in indentation", + "initMethodSelfParamTypeVar": "Type annotation for \"self\" parameter of \"__init__\" method cannot contain class-scoped type varaiables", "initSubclassClsParam": "__init_subclass__ override should take a \"cls\" parameter", "initSubclassCallFailed": "Incorrect keyword arguments for __init_subclass__ method", "initVarNotAllowed": "\"InitVar\" is not allowed in this context", @@ -275,9 +277,9 @@ "matchIncompatible": "Match statements require Python 3.10 or newer", "matchIsNotExhaustive": "Cases within match statement do not exhaustively handle all values", "maxParseDepthExceeded": "Maximum parse depth exceeded; break expression into smaller sub-expressions", - "memberAccess": "Cannot access member \"{name}\" for type \"{type}\"", - "memberDelete": "Cannot delete member \"{name}\" for type \"{type}\"", - "memberSet": "Cannot assign member \"{name}\" for type \"{type}\"", + "memberAccess": "Cannot access attribute \"{name}\" for class \"{type}\"", + "memberDelete": "Cannot delete attribute \"{name}\" for class \"{type}\"", + "memberSet": "Cannot assign to attribute \"{name}\" for class \"{type}\"", "metaclassConflict": "The metaclass of a derived class must be a subclass of the metaclasses of all its base classes", "metaclassDuplicate": "Only one metaclass can be provided", "metaclassIsGeneric": "Metaclass cannot be generic", @@ -289,7 +291,7 @@ "missingSuperCall": "Method \"{methodName}\" does not call the method of the same name in parent class", "moduleAsType": "Module cannot be used as a type", "moduleNotCallable": "Module is not callable", - "moduleUnknownMember": "\"{memberName}\" is not a known member of module \"{moduleName}\"", + "moduleUnknownMember": "\"{memberName}\" is not a known attribute of module \"{moduleName}\"", "namedExceptAfterCatchAll": "A named except clause cannot appear after catch-all except clause", "namedParamAfterParamSpecArgs": "Keyword parameter \"{name}\" cannot appear in signature after ParamSpec args parameter", "namedTupleEmptyName": "Names within a named tuple cannot be empty", @@ -315,7 +317,7 @@ "noneOperator": "Operator \"{operator}\" not supported for \"None\"", "noneNotSubscriptable": "Object of type \"None\" is not subscriptable", "noneNotUsableWith": "Object of type \"None\" cannot be used with \"with\"", - "noneUnknownMember": "\"{name}\" is not a known member of \"None\"", + "noneUnknownMember": "\"{name}\" is not a known attribute of \"None\"", "nonLocalNoBinding": "No binding for nonlocal \"{name}\" found", "nonLocalReassignment": "\"{name}\" is assigned before nonlocal declaration", "nonLocalRedefinition": "\"{name}\" was already declared nonlocal", @@ -353,18 +355,18 @@ "paramAlreadyAssigned": "Parameter \"{name}\" is already assigned", "paramAnnotationMissing": "Type annotation is missing for parameter \"{name}\"", "paramNameMissing": "No parameter named \"{name}\"", - "paramSpecArgsKwargsUsage": "\"args\" and \"kwargs\" members of ParamSpec must both appear within a function signature", + "paramSpecArgsKwargsUsage": "\"args\" and \"kwargs\" attributes of ParamSpec must both appear within a function signature", "paramSpecArgsMissing": "Arguments for ParamSpec \"{type}\" are missing", - "paramSpecArgsUsage": "\"args\" member of ParamSpec is valid only when used with *args parameter", + "paramSpecArgsUsage": "\"args\" attribute of ParamSpec is valid only when used with *args parameter", "paramSpecAssignedName": "ParamSpec must be assigned to a variable named \"{name}\"", "paramSpecContext": "ParamSpec is not allowed in this context", "paramSpecDefaultNotTuple": "Expected ellipsis, a tuple expression, or ParamSpec for default value of ParamSpec", "paramSpecFirstArg": "Expected name of ParamSpec as first argument", - "paramSpecKwargsUsage": "\"kwargs\" member of ParamSpec is valid only when used with **kwargs parameter", + "paramSpecKwargsUsage": "\"kwargs\" attribute of ParamSpec is valid only when used with **kwargs parameter", "paramSpecNotUsedByOuterScope": "ParamSpec \"{name}\" has no meaning in this context", "paramSpecScopedToReturnType": "ParamSpec \"{name}\" is scoped to a callable within the return type and cannot be referenced in the function body", "paramSpecUnknownArg": "ParamSpec does not support more than one argument", - "paramSpecUnknownMember": "\"{name}\" is not a known member of ParamSpec", + "paramSpecUnknownMember": "\"{name}\" is not a known attribute of ParamSpec", "paramSpecUnknownParam": "\"{name}\" is unknown parameter to ParamSpec", "paramAssignmentMismatch": "Expression of type \"{sourceType}\" cannot be assigned to parameter of type \"{paramType}\"", "paramTypeCovariant": "Covariant type variable cannot be used in parameter type", @@ -410,7 +412,7 @@ "returnOutsideFunction": "\"return\" can be used only within a function", "returnMissing": "Function with declared return type \"{returnType}\" must return value on all code paths", "returnTypeContravariant": "Contravariant type variable cannot be used in return type", - "returnTypeMismatch": "Expression of type \"{exprType}\" cannot be assigned to return type \"{returnType}\"", + "returnTypeMismatch": "Expression of type \"{exprType}\" is incompatible with return type \"{returnType}\"", "returnTypeUnknown": "Return type is unknown", "returnTypeAny": "Return type is Any", "returnTypePartiallyUnknown": "Return type, \"{returnType}\", is partially unknown", @@ -477,8 +479,8 @@ "typeArgsMissingForClass": "Expected type arguments for generic class \"{name}\"", "typeArgsTooFew": "Too few type arguments provided for \"{name}\"; expected {expected} but received {received}", "typeArgsTooMany": "Too many type arguments provided for \"{name}\"; expected {expected} but received {received}", - "typeAssignmentMismatch": "Expression of type \"{sourceType}\" cannot be assigned to declared type \"{destType}\"", - "typeAssignmentMismatchWildcard": "Import symbol \"{name}\" has type \"{sourceType}\", which cannot be assigned to declared type \"{destType}\"", + "typeAssignmentMismatch": "Expression of type \"{sourceType}\" is incompatible with declared type \"{destType}\"", + "typeAssignmentMismatchWildcard": "Import symbol \"{name}\" has type \"{sourceType}\", which is incompatible with declared type \"{destType}\"", "typeCallNotAllowed": "type() call should not be used in type annotation", "typeCheckOnly": "\"{name}\" is marked as @type_check_only and can be used only in type annotations", "typeCommentDeprecated": "Use of type comments is deprecated; use type annotation instead", @@ -535,7 +537,7 @@ "typeVarDefaultIllegal": "Type variable default types require Python 3.13 or newer", "typeVarDefaultInvalidTypeVar": "Type parameter \"{name}\" has a default type that refers to one or more type variables that are out of scope", "typeVarFirstArg": "Expected name of TypeVar as first argument", - "typeVarNoMember": "TypeVar \"{type}\" has no member \"{name}\"", + "typeVarNoMember": "TypeVar \"{type}\" has no attribute \"{name}\"", "typeVarNotSubscriptable": "TypeVar \"{type}\" is not subscriptable", "typeVarNotUsedByOuterScope": "Type variable \"{name}\" has no meaning in this context", "typeVarPossiblyUnsolvable": "Type variable \"{name}\" may go unsolved if caller supplies no argument for parameter \"{param}\"", @@ -633,7 +635,7 @@ "argsPositionOnly": "Position-only parameter mismatch; expected {expected} but received {received}", "argumentType": "Argument type is \"{type}\"", "argumentTypes": "Argument types: ({types})", - "assignToNone": "Type cannot be assigned to type \"None\"", + "assignToNone": "Type is incompatible with \"None\"", "asyncHelp": "Did you mean \"async with\"?", "baseClassIncompatible": "Base class \"{baseClass}\" is incompatible with type \"{type}\"", "baseClassIncompatibleSubclass": "Base class \"{baseClass}\" derives from \"{subclass}\" which is incompatible with type \"{type}\"", @@ -669,30 +671,30 @@ "invariantSuggestionSet": "Consider switching from \"set\" to \"Container\" which is covariant", "kwargsParamMissing": "Parameter \"**{paramName}\" has no corresponding parameter", "listAssignmentMismatch": "Type \"{type}\" is incompatible with target list", - "literalAssignmentMismatch": "\"{sourceType}\" cannot be assigned to type \"{destType}\"", + "literalAssignmentMismatch": "\"{sourceType}\" is incompatible with type \"{destType}\"", "matchIsNotExhaustiveType": "Unhandled type: \"{type}\"", "matchIsNotExhaustiveHint": "If exhaustive handling is not intended, add \"case _: pass\"", - "memberSetClassVar": "Member \"{name}\" cannot be assigned through a class instance because it is a ClassVar", - "memberAssignment": "Expression of type \"{type}\" cannot be assigned to member \"{name}\" of class \"{classType}\"", + "memberSetClassVar": "Attribute \"{name}\" cannot be assigned through a class instance because it is a ClassVar", + "memberAssignment": "Expression of type \"{type}\" cannot be assigned to attribute \"{name}\" of class \"{classType}\"", "memberIsAbstract": "\"{type}.{name}\" is not implemented", "memberIsAbstractMore": "and {count} more...", "memberIsClassVarInProtocol": "\"{name}\" is defined as a ClassVar in protocol", "memberIsFinalInProtocol": "\"{name}\" is marked Final in protocol", - "memberIsInitVar": "Member \"{name}\" is an init-only field", + "memberIsInitVar": "\"{name}\" is an init-only field", "memberIsInvariant": "\"{name}\" is invariant because it is mutable", "memberIsNotClassVarInClass": "\"{name}\" must be defined as a ClassVar to be compatible with protocol", "memberIsNotClassVarInProtocol": "\"{name}\" is not defined as a ClassVar in protocol", "memberIsNotFinalInProtocol": "\"{name}\" is not marked Final in protocol", "memberIsWritableInProtocol": "\"{name}\" is writable in protocol", "memberTypeMismatch": "\"{name}\" is an incompatible type", - "memberUnknown": "Member \"{name}\" is unknown", + "memberUnknown": "Attribute \"{name}\" is unknown", "metaclassConflict": "Metaclass \"{metaclass1}\" conflicts with \"{metaclass2}\"", "missingGetter": "Property getter method is missing", "missingSetter": "Property setter method is missing", "missingDeleter": "Property deleter method is missing", "namedParamMissingInDest": "Keyword parameter \"{name}\" is missing in destination", "namedParamMissingInSource": "Keyword parameter \"{name}\" is missing in source", - "namedParamTypeMismatch": "Keyword parameter \"{name}\" of type \"{sourceType}\" cannot be assigned to type \"{destType}\"", + "namedParamTypeMismatch": "Keyword parameter \"{name}\" of type \"{sourceType}\" is incompatible with type \"{destType}\"", "namedTupleNotAllowed": "NamedTuple cannot be used for instance or class checks", "newMethodLocation": "The __new__ method is defined in class \"{type}\"", "newMethodSignature": "Signature of __new__ is \"{type}\"", @@ -724,7 +726,7 @@ "overridePositionalParamCount": "Positional parameter count mismatch; base method has {baseCount}, but override has {overrideCount}", "overrideReturnType": "Return type mismatch: base method returns type \"{baseType}\", override returns type \"{overrideType}\"", "overrideType": "Base class defines type as \"{type}\"", - "paramAssignment": "Parameter {index}: type \"{sourceType}\" cannot be assigned to type \"{destType}\"", + "paramAssignment": "Parameter {index}: type \"{sourceType}\" is incompatible with type \"{destType}\"", "paramSpecMissingInOverride": "ParamSpec parameters are missing in override method", "paramType": "Parameter type is \"{paramType}\"", "privateImportFromPyTypedSource": "Import from \"{module}\" instead", @@ -754,7 +756,7 @@ "tupleSizeMismatch": "Tuple size mismatch; expected {expected} but received {received}", "tupleSizeMismatchIndeterminateDest": "Tuple size mismatch; expected {expected} or more but received {received}", "typeAliasInstanceCheck": "Type alias created with \"type\" statement cannot be used with instance and class checks", - "typeAssignmentMismatch": "Type \"{sourceType}\" cannot be assigned to type \"{destType}\"", + "typeAssignmentMismatch": "Type \"{sourceType}\" is incompatible with type \"{destType}\"", "typeBound": "Type \"{sourceType}\" is incompatible with bound type \"{destType}\" for type variable \"{name}\"", "typeConstrainedTypeVar": "Type \"{type}\" is incompatible with constrained type variable \"{name}\"", "typedDictBaseClass": "Class \"{type}\" is not a TypedDict", diff --git a/packages/pyright-internal/src/localization/package.nls.es.json b/packages/pyright-internal/src/localization/package.nls.es.json index b2f2971f63..dd3a4c411d 100644 --- a/packages/pyright-internal/src/localization/package.nls.es.json +++ b/packages/pyright-internal/src/localization/package.nls.es.json @@ -104,7 +104,7 @@ "dataClassFieldWithDefault": "Los campos sin valores predeterminados no pueden aparecer después de los campos con valores predeterminados", "dataClassFieldWithPrivateName": "El campo Dataclass no puede utilizar un nombre privado", "dataClassFieldWithoutAnnotation": "El campo Dataclass sin anotación de tipo provocará una excepción en tiempo de ejecución", - "dataClassPostInitParamCount": "Dataclass __post_init__ recuento de parámetros incorrecto; el número de campos InitVar es {esperado}.", + "dataClassPostInitParamCount": "Dataclass __post_init__ recuento de parámetros incorrecto; el número de campos InitVar es {expected}.", "dataClassPostInitType": "El tipo de parámetro del método __post_init__ de la clase de datos no coincide con el del campo \"{fieldName}\".", "dataClassSlotsOverwrite": "__slots__ ya está definido en la clase", "dataClassTransformExpectedBoolLiteral": "Expresión esperada que se evalúa estáticamente como True o False", @@ -255,7 +255,7 @@ "initVarNotAllowed": "\"InitVar\" no se permite en este contexto", "instanceMethodSelfParam": "Los métodos de instancia deben tomar un parámetro \"auto\"", "instanceVarOverridesClassVar": "La variable de instancia \"{name}\" invalida la variable de clase del mismo nombre en la clase \"{className}\"", - "instantiateAbstract": "No se puede instanciar la clase abstracta \"{tipo}\"", + "instantiateAbstract": "No se puede instanciar la clase abstracta \"{type}\"", "instantiateProtocol": "No se puede crear una instancia de la clase de protocolo \"{type}\"", "internalBindError": "Se ha producido un error interno al vincular el archivo \"{file}\": {message}", "internalParseError": "Se ha producido un error interno al procesar el archivo \"{file}\": {message}", @@ -597,7 +597,7 @@ "unpackedDictArgumentNotMapping": "La expresión del argumento después de ** debe ser un mapeo con un tipo de clave \"str\".", "unpackedDictSubscriptIllegal": "El operador de desempaquetado del diccionario en el subíndice no está permitido", "unpackedSubscriptIllegal": "El operador de desempaquetado en el subíndice requiere Python 3.11 o posterior.", - "unpackedTypeVarTupleExpected": "Se espera un TypeVarTuple desempaquetado; use Unpack[{nombre1}] o *{name2}", + "unpackedTypeVarTupleExpected": "Se espera un TypeVarTuple desempaquetado; use Unpack[{name1}] o *{name2}", "unpackedTypedDictArgument": "No se puede emparejar el argumento TypedDict desempaquetado con los parámetros", "unreachableCode": "El código es inalcanzable", "unreachableExcept": "La cláusula Excepto es inalcanzable porque la excepción ya está administrada", @@ -667,7 +667,7 @@ "keyUndefined": "\"{name}\" no es una clave definida en \"{type}\"", "kwargsParamMissing": "El parámetro \"**{paramName}\" no tiene ningún parámetro correspondiente.", "listAssignmentMismatch": "El tipo \"{type}\" es incompatible con la lista de objetivos", - "literalAssignmentMismatch": "\"{sourceType}\" no puede asignarse al tipo \"{tipoDest}\"", + "literalAssignmentMismatch": "\"{sourceType}\" no puede asignarse al tipo \"{destType}\"", "matchIsNotExhaustiveHint": "Si no se pretende un tratamiento exhaustivo, agregue \"case _: pass\"", "matchIsNotExhaustiveType": "Tipo no manejado: \"{type}\"", "memberAssignment": "La expresión de tipo \"{type}\" no se puede asignar al miembro \"{name}\" de la clase \"{classType}\"", @@ -784,6 +784,7 @@ "typedDictFieldTypeMismatch": "El tipo \"{type}\" no se puede asignar al elemento \"{name}\"", "typedDictFieldUndefined": "\"{name}\" es un elemento no definido en el tipo \"{type}\"", "typedDictFinalMismatch": "\"{sourceType}\" no es compatible con \"{destType}\" debido a una discrepancia @final", + "typedDictKeyAccess": "Utilizar [\"{name}\"] para hacer referencia al elemento en TypedDict", "typedDictNotAllowed": "No se puede usar TypedDict para comprobaciones de instancia o clase", "unhashableType": "El tipo \"{type}\" no admite hash", "uninitializedAbstractVariable": "La variable de instancia \"{name}\" está definida en la clase base abstracta \"{classType} \" pero no inicializada.", diff --git a/packages/pyright-internal/src/localization/package.nls.fr.json b/packages/pyright-internal/src/localization/package.nls.fr.json index 2db1160c54..c4109342c2 100644 --- a/packages/pyright-internal/src/localization/package.nls.fr.json +++ b/packages/pyright-internal/src/localization/package.nls.fr.json @@ -89,7 +89,7 @@ "concatenateParamSpecMissing": "Le dernier argument de type pour « Concatener » doit être un ParamSpec ou bien « ... »", "concatenateTypeArgsMissing": "\"Concaténation\" nécessite au moins deux arguments de type", "conditionalOperandInvalid": "Opérande conditionnel non valide de type \"{type}\"", - "constantRedefinition": "\"{nom}\" est constant (car il est en majuscule) et ne peut pas être redéfini", + "constantRedefinition": "\"{name}\" est constant (car il est en majuscule) et ne peut pas être redéfini", "constructorNoArgs": "Aucun argument attendu pour le constructeur « {type} »", "constructorParametersMismatch": "Non-concordance entre la signature de __new__ et __init__ dans la classe \"{classType}\"", "containmentAlwaysFalse": "L'expression sera toujours évaluée à False car les types \"{leftType}\" et \"{rightType}\" ne se chevauchent pas", @@ -480,7 +480,7 @@ "typeArgsMissingForAlias": "Arguments de type attendus pour l’alias de type générique « {name} »", "typeArgsMissingForClass": "Arguments de type attendus pour la classe générique \"{name}\"", "typeArgsTooFew": "Trop peu d’arguments de type fournis pour « {name} » ; {expected} attendu, mais {received} reçu", - "typeArgsTooMany": "Trop d'arguments de type fournis pour \"{name}\" ; attendu {attendu} mais reçu {reçu}", + "typeArgsTooMany": "Trop d'arguments de type fournis pour \"{name}\" ; attendu {expected} mais reçu {received}", "typeAssignmentMismatch": "Impossible d’affecter l’expression de type « {sourceType} » au type déclaré « {destType} »", "typeAssignmentMismatchWildcard": "Le symbole d’importation « {name} » a le type « {sourceType} », qui ne peut pas être affecté au type déclaré « {destType} »", "typeCallNotAllowed": "l’appel type() ne doit pas être utilisé dans l’annotation de type", @@ -628,7 +628,7 @@ "argParam": "L’argument correspond au paramètre « {paramName} »", "argParamFunction": "L’argument correspond au paramètre « {paramName} » dans la fonction « {functionName} »", "argsParamMissing": "Le paramètre \"*{paramName}\" n'a pas de paramètre correspondant", - "argsPositionOnly": "Non-concordance des paramètres de position uniquement ; attendu {attendu} mais reçu {reçu}", + "argsPositionOnly": "Non-concordance des paramètres de position uniquement ; attendu {expected} mais reçu {received}", "argumentType": "Le type d’argument est « {type} »", "argumentTypes": "Types d'argument : ({types})", "assignToNone": "Le type ne peut pas être affecté au type « None »", @@ -758,7 +758,7 @@ "typeIncompatible": "« {sourceType} » n’est pas compatible avec « {destType} »", "typeNotClass": "« {type} » n’est pas une classe", "typeNotStringLiteral": "\"{type}\" n'est pas un littéral de chaîne", - "typeOfSymbol": "Le type de \"{nom}\" est \"{type}\"", + "typeOfSymbol": "Le type de \"{name}\" est \"{type}\"", "typeParamSpec": "Le type « {type} » n’est pas compatible avec ParamSpec « {name} »", "typeUnsupported": "Le type « {type} » n’est pas pris en charge", "typeVarDefaultOutOfScope": "La variable de type « {name} » n’est pas dans l’étendue", @@ -784,6 +784,7 @@ "typedDictFieldTypeMismatch": "Le type « {type} » n'est pas attribuable à l’élément « {name} »", "typedDictFieldUndefined": "« {name} » est un élément non défini dans le type « {type} »", "typedDictFinalMismatch": "« {sourceType} » n’est pas compatible avec « {destType} » en raison d’une incompatibilité de @final", + "typedDictKeyAccess": "Utilisez [« {name} »] pour référencer l’élément dans TypedDict", "typedDictNotAllowed": "TypedDict ne peut pas être utilisé pour les vérifications d’instance ou de classe", "unhashableType": "Le type \"{type}\" n'est pas hachable", "uninitializedAbstractVariable": "La variable d’instance « {name} » est définie dans la classe de base abstraite « {classType} » mais n’est pas initialisée", diff --git a/packages/pyright-internal/src/localization/package.nls.it.json b/packages/pyright-internal/src/localization/package.nls.it.json index c9507a6dfa..97c6758d33 100644 --- a/packages/pyright-internal/src/localization/package.nls.it.json +++ b/packages/pyright-internal/src/localization/package.nls.it.json @@ -717,7 +717,7 @@ "overrideParamNameExtra": "Parametro \"{name}\" mancante nella base", "overrideParamNameMissing": "Parametro \"{name}\" mancante nell'override", "overrideParamNamePositionOnly": "Mancata corrispondenza del parametro {index}: il parametro di base \"{baseName}\" è un parametro di parola chiave, il parametro di override è di sola posizione", - "overrideParamNoDefault": "Parametro \"{name}\" non corrispondente: il parametro di base ha un valore di argomento predefinito, il parametro di override non è", + "overrideParamNoDefault": "Parametro \"{index}\" non corrispondente: il parametro di base ha un valore di argomento predefinito, il parametro di override non è", "overrideParamType": "Tipo di parametro {index} non corrispondente: il parametro di base è di tipo \"{baseType}\", il parametro di override è di tipo \"{overrideType}\"", "overridePositionalParamCount": "Numero di parametri posizionali non corrispondente. Il metodo di base ne ha {baseCount}, ma l'override ne ha {overrideCount}", "overrideReturnType": "Tipo restituito non corrispondente: il metodo di base restituisce il tipo \"{baseType}\", l'override restituisce il tipo \"{overrideType}\"", @@ -784,6 +784,7 @@ "typedDictFieldTypeMismatch": "Il tipo \"{type}\" non può essere assegnato all’elemento \"{name}\"", "typedDictFieldUndefined": "\"{name}\" è un elemento non definito nel tipo \"{type}\"", "typedDictFinalMismatch": "\"{sourceType}\" non è compatibile con \"{destType}\" a causa di una @final mancata corrispondenza", + "typedDictKeyAccess": "Usare [\"{name}\"] per fare riferimento all'elemento in TypedDict", "typedDictNotAllowed": "Non è possibile usare TypedDict per i controlli di istanze o classi", "unhashableType": "Il tipo \"{type}\" non è hashable", "uninitializedAbstractVariable": "La variabile di istanza \"{name}\" è definita nella classe di base astratta \"{classType}\" ma non è inizializzata", diff --git a/packages/pyright-internal/src/localization/package.nls.ja.json b/packages/pyright-internal/src/localization/package.nls.ja.json index 4d1d207f7d..e3370db47a 100644 --- a/packages/pyright-internal/src/localization/package.nls.ja.json +++ b/packages/pyright-internal/src/localization/package.nls.ja.json @@ -784,6 +784,7 @@ "typedDictFieldTypeMismatch": "型 \"{type}\" は、アイテム \"{name}\" に割り当てできません", "typedDictFieldUndefined": "\"{name}\" は型 \"{type}\" の未定義のアイテムです", "typedDictFinalMismatch": "@final が一致しないため、\"{sourceType}\" は \"{destType}\" と互換性がありません", + "typedDictKeyAccess": "[\"{name}\"] を使用して TypedDict の項目を参照する", "typedDictNotAllowed": "TypedDict はインスタンスまたはクラスのチェックには使用できません", "unhashableType": "型 \"{type}\" はハッシュ可能ではありません", "uninitializedAbstractVariable": "インスタンス変数 \"{name}\" は抽象基本クラス \"{classType}\" で定義されていますが、初期化されていません", diff --git a/packages/pyright-internal/src/localization/package.nls.ko.json b/packages/pyright-internal/src/localization/package.nls.ko.json index 2fffa8746f..d1d38399ce 100644 --- a/packages/pyright-internal/src/localization/package.nls.ko.json +++ b/packages/pyright-internal/src/localization/package.nls.ko.json @@ -496,8 +496,8 @@ "typeNotSpecializable": "‘{type}’ 형식을 특수화할 수 없습니다.", "typeNotSubscriptable": "\"{type}\" 형식의 개체를 첨자할 수 없습니다.", "typeNotSupportBinaryOperator": "‘{operator}’ 연산자는 ‘{leftType}’ 및 ‘{rightType}’ 형식에 대해 지원되지 않습니다.", - "typeNotSupportBinaryOperatorBidirectional": "예상 형식이 ‘{expectedType}’인 경우 ‘{type}’ 형식에 대해 ‘{operator}’ 연산자가 지원되지 않습니다.", - "typeNotSupportUnaryOperator": "‘None‘에 대해 ’{operator}‘ 연산자가 지원되지 않습니다.", + "typeNotSupportBinaryOperatorBidirectional": "예상 형식이 ‘{expectedType}’인 경우 ‘{leftType}’ 및 ‘{rightType}’ 형식에 대해 ‘{operator}’ 연산자가 지원되지 않습니다.", + "typeNotSupportUnaryOperator": "‘{type}’‘에 대해 ’{operator}‘ 연산자가 지원되지 않습니다.", "typeNotSupportUnaryOperatorBidirectional": "예상 형식이 \"{expectedType}\" 경우 형식 \"{type}\"에 대해 연산자 \"{operator}\"이(가) 지원되지 않습니다.", "typeNotUsableWith": "\"{type}\" 형식의 개체는 {method}을(를) 구현하지 않으므로 \"with\"와 함께 사용할 수 없습니다.", "typeParameterBoundNotAllowed": "바운드 또는 제약 조건은 가변 인자 형식 매개 변수 또는 ParamSpec와 함께 사용할 수 없습니다.", @@ -718,7 +718,7 @@ "overrideParamNameMissing": "재정의에 ‘{name}’ 매개 변수가 없습니다.", "overrideParamNamePositionOnly": "매개 변수 {index} 불일치: 기본 매개 변수 \"{baseName}\"은(는) 키워드 매개 변수이며 재정의 매개 변수는 위치 전용임", "overrideParamNoDefault": "{index} 매개 변수가 불일치합니다. 기본 매개 변수에 기본 인수 값이 있습니다. 재정의 매개 변수에는 없습니다.", - "overrideParamType": "‘{name}’ 매개 변수 형식이 일치하지 않습니다. 기본 매개 변수는 형식이 ‘{baseType}’, 재정의 매개 변수는 형식이 ‘{overrideType}’입니다.", + "overrideParamType": "‘{index}’ 매개 변수 형식이 일치하지 않습니다. 기본 매개 변수는 형식이 ‘{baseType}’, 재정의 매개 변수는 형식이 ‘{overrideType}’입니다.", "overridePositionalParamCount": "위치 매개 변수 개수가 일치하지 않습니다. 기본 메서드에 {baseCount}개가 있지만 재정의에는 {overrideCount}개가 있습니다.", "overrideReturnType": "반환 형식 불일치: 기본 메서드는 \"{baseType}\" 형식을 반환하고 재정의는 \"{overrideType}\" 형식을 반환합니다.", "overrideType": "기본 클래스는 형식을 \"{type}\"으로 정의합니다.", @@ -784,6 +784,7 @@ "typedDictFieldTypeMismatch": "\"{type}\" 형식은 \"{name}\" 항목에 할당할 수 없습니다.", "typedDictFieldUndefined": "\"{name}\"은(는) \"{type}\" 형식의 정의되지 않은 항목입니다.", "typedDictFinalMismatch": "@final 불일치로 인해 \"{sourceType}\"이(가) \"{destType}\"과(와) 호환되지 않습니다.", + "typedDictKeyAccess": "TypedDict에서 항목을 참조하려면 [\"{name}\"]을(를) 사용하세요.", "typedDictNotAllowed": "TypedDict는 인스턴스 또는 클래스 검사에 사용할 수 없습니다.", "unhashableType": "‘{type}’ 형식을 해시할 수 없습니다.", "uninitializedAbstractVariable": "인스턴스 변수 \"{name}\"이(가) 추상 기본 클래스 \"{classType}\"에 정의되어 있지만 초기화되지 않았습니다.", diff --git a/packages/pyright-internal/src/localization/package.nls.pl.json b/packages/pyright-internal/src/localization/package.nls.pl.json index 11e489966f..d758775933 100644 --- a/packages/pyright-internal/src/localization/package.nls.pl.json +++ b/packages/pyright-internal/src/localization/package.nls.pl.json @@ -257,9 +257,9 @@ "instanceVarOverridesClassVar": "Zmienna wystąpienia „{name}” zastępuje zmienną klasy o tej samej nazwie w klasie „{className}”", "instantiateAbstract": "Nie można utworzyć wystąpienia klasy abstrakcyjnej „{type}”", "instantiateProtocol": "Nie można utworzyć wystąpienia klasy protokołu typu „{type}”", - "internalBindError": "Wystąpił błąd wewnętrzny podczas wiązania pliku „{plik}”: {message}", - "internalParseError": "Wystąpił błąd wewnętrzny podczas analizowania pliku „{plik}”: {message}", - "internalTypeCheckingError": "Wystąpił błąd wewnętrzny podczas sprawdzania typu pliku „{plik}”: {message}", + "internalBindError": "Wystąpił błąd wewnętrzny podczas wiązania pliku „{file}”: {message}", + "internalParseError": "Wystąpił błąd wewnętrzny podczas analizowania pliku „{file}”: {message}", + "internalTypeCheckingError": "Wystąpił błąd wewnętrzny podczas sprawdzania typu pliku „{file}”: {message}", "invalidIdentifierChar": "Nieprawidłowy znak w identyfikatorze", "invalidStubStatement": "Instrukcja nie ma znaczenia w pliku zastępczym typu", "invalidTokenChars": "Nieprawidłowy znak „{text}” w tokenie", @@ -784,6 +784,7 @@ "typedDictFieldTypeMismatch": "Nie można przypisać typu „{type}” do elementu „{name}”", "typedDictFieldUndefined": "Nazwa „{name}” jest niezdefiniowanym elementem w typie „{type}”", "typedDictFinalMismatch": "Typ „{sourceType}” jest niezgodny z typem „{destType}” z powodu niezgodności @final", + "typedDictKeyAccess": "Użyj elementu [\"{name}\"], aby odwołać się do elementu w TypedDict", "typedDictNotAllowed": "Funkcja TypedDict nie może być używana do sprawdzania wystąpień lub klas", "unhashableType": "Typ „{type}” nie jest wartością skrótu", "uninitializedAbstractVariable": "zmienna wystąpienia „{name}” jest zdefiniowana w abstrakcyjnej klasie bazowej „{classType}” ale nie została zainicjowana", diff --git a/packages/pyright-internal/src/localization/package.nls.pt-br.json b/packages/pyright-internal/src/localization/package.nls.pt-br.json index 731bab5d42..c42a8ca812 100644 --- a/packages/pyright-internal/src/localization/package.nls.pt-br.json +++ b/packages/pyright-internal/src/localization/package.nls.pt-br.json @@ -784,6 +784,7 @@ "typedDictFieldTypeMismatch": "O tipo \"{type}\" não é atribuível ao item \"{name}\"", "typedDictFieldUndefined": "\"{name}\" é um item indefinido no tipo \"{type}\"", "typedDictFinalMismatch": "\"{sourceType}\" é incompatível com \"{destType}\" devido a uma @final incompatível", + "typedDictKeyAccess": "Usar [\"{name}\"] para fazer referência ao item em TypedDict", "typedDictNotAllowed": "TypedDict não pode ser usado para verificações de instância ou de classe", "unhashableType": "O tipo \"{type}\" não é pode fazer hash", "uninitializedAbstractVariable": "A variável de instância \"{name}\" está definida na classe base abstrata \"{classType}\", mas não foi inicializada", diff --git a/packages/pyright-internal/src/localization/package.nls.qps-ploc.json b/packages/pyright-internal/src/localization/package.nls.qps-ploc.json index 739d13d948..ebf94122c7 100644 --- a/packages/pyright-internal/src/localization/package.nls.qps-ploc.json +++ b/packages/pyright-internal/src/localization/package.nls.qps-ploc.json @@ -784,6 +784,7 @@ "typedDictFieldTypeMismatch": "[XYIBH][นั้Tÿpë \"{tÿpë}\" ïs ñøt æssïgñæþlë tø ïtëm \"{ñæmë}\"Ấğ倪İЂҰक्र्तिृまẤğ倪İЂนั้ढूँ]", "typedDictFieldUndefined": "[UsDC9][นั้\"{ñæmë}\" ïs æñ µñðëfïñëð ïtëm ïñ tÿpë \"{tÿpë}\"Ấğ倪İЂҰक्र्तिृまẤğ倪İนั้ढूँ]", "typedDictFinalMismatch": "[tFb04][นั้\"{søµrçëTÿpë}\" ïs ïñçømpætïþlë wïth \"{ðëstTÿpë}\" þëçæµsë øf æ @fïñæl mïsmætçhẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪นั้ढूँ]", + "typedDictKeyAccess": "[67DLq][นั้Üsë [\"{ñæmë}\"] tø rëfërëñçë ïtëm ïñ TÿpëðÐïçtẤğ倪İЂҰक्र्तिृまẤğ倪İนั้ढूँ]", "typedDictNotAllowed": "[eTsPP][นั้TÿpëðÐïçt çæññøt þë µsëð før ïñstæñçë ør çlæss çhëçksẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्นั้ढूँ]", "unhashableType": "[IJEeq][นั้Tÿpë \"{tÿpë}\" ïs ñøt hæshæþlëẤğ倪İЂҰक्र्तिृนั้ढूँ]", "uninitializedAbstractVariable": "[uDuHt][นั้Ïñstæñçë værïæþlë \"{ñæmë}\" ïs ðëfïñëð ïñ æþstræçt þæsë çlæss \"{çlæssTÿpë}\" þµt ñøt ïñïtïælïzëðẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्นั้ढूँ]", diff --git a/packages/pyright-internal/src/localization/package.nls.ru.json b/packages/pyright-internal/src/localization/package.nls.ru.json index b70809c041..b73b9605b5 100644 --- a/packages/pyright-internal/src/localization/package.nls.ru.json +++ b/packages/pyright-internal/src/localization/package.nls.ru.json @@ -690,7 +690,7 @@ "missingSetter": "Отсутствует метод установки свойств", "namedParamMissingInDest": "В целевом объекте отсутствует параметр ключевого слова \"{name}\"", "namedParamMissingInSource": "В источнике нет параметра ключевого слова \"{name}\"", - "namedParamTypeMismatch": "Параметр ключевого слова {index} типа \"{sourceType}\" нельзя присвоить типу \"{destType}\"", + "namedParamTypeMismatch": "Параметр ключевого слова {name} типа \"{sourceType}\" нельзя присвоить типу \"{destType}\"", "namedTupleNotAllowed": "NamedTuple не может использоваться для проверок экземпляров или классов", "newMethodLocation": "Метод __new__ определен в классе \"{type}\"", "newMethodSignature": "Сигнатура метода __new__ требует \"{type}\"", @@ -784,6 +784,7 @@ "typedDictFieldTypeMismatch": "Тип \"{type}\" нельзя присвоить полю \"{name}\"", "typedDictFieldUndefined": "Элемент \"{name}\" не определен в типе \"{type}\"", "typedDictFinalMismatch": "\"{sourceType}\" несовместим с \"{destType}\" из-за несоответствия окончательности", + "typedDictKeyAccess": "Использовать [\"{name}\"] для ссылки на элемент в TypedDict", "typedDictNotAllowed": "TypedDict не может использоваться для проверок экземпляров или классов", "unhashableType": "Тип \"{type}\" не является хэшируемым", "uninitializedAbstractVariable": "Переменная экземпляра \"{name}\" определена в абстрактном базовом классе \"{classType}\", но не инициализирована", diff --git a/packages/pyright-internal/src/localization/package.nls.tr.json b/packages/pyright-internal/src/localization/package.nls.tr.json index 280bdd6163..2d08a1350f 100644 --- a/packages/pyright-internal/src/localization/package.nls.tr.json +++ b/packages/pyright-internal/src/localization/package.nls.tr.json @@ -21,8 +21,8 @@ "annotationNotSupported": "Tür ek açıklaması bu deyim için desteklenmiyor", "annotationSpansStrings": "Tür ek açıklamaları birden çok dize sabit değerine yayılamaz", "annotationStringEscape": "Tür ek açıklamaları kaçış karakterleri içeremez", - "argAssignment": "\"{argType}\" türünde bağımsız değişken, \"{paramName}\" türündeki parametreye atanamaz", - "argAssignmentFunction": "\"{argType}\" türünde bağımsız değişken, \"{functionName}\" işlevi içinde \"{paramName}\" türündeki parametreye atanamaz", + "argAssignment": "\"{argType}\" türünde bağımsız değişken, \"{paramType}\" türündeki parametreye atanamaz", + "argAssignmentFunction": "\"{argType}\" türünde bağımsız değişken, \"{functionName}\" işlevi içinde \"{paramType}\" türündeki parametreye atanamaz", "argAssignmentParam": "\"{argType}\" türünde bağımsız değişken, \"{paramName}\" türündeki \"{paramType}\" parametresine atanamaz", "argAssignmentParamFunction": "\"{argType}\" türünde bağımsız değişken, \"{functionName}\" işlevi içinde \"{paramName}\" türündeki \"{paramType}\" parametresine atanamaz", "argMissingForParam": "{name} parametresi için bağımsız değişken eksik", @@ -784,6 +784,7 @@ "typedDictFieldTypeMismatch": "\"{type}\" türü \"{name}\" öğesine atanamaz", "typedDictFieldUndefined": "\"{name}\", \"{type}\" türündeki tanımsız bir öğedir", "typedDictFinalMismatch": "\"{sourceType}\" @final uyumsuzluğu nedeniyle \"{destType}\" ile uyumsuz", + "typedDictKeyAccess": "TypedDict’te öğeye başvurmak için [\"{name}\"] değerini kullanın", "typedDictNotAllowed": "TypedDict örnek veya sınıf kontrolleri için kullanılamaz", "unhashableType": "\"{type}\" türü karmalanabilir değil", "uninitializedAbstractVariable": "\"{name}\" örnek değişkeni, \"{classType}\" soyut temel sınıfında tanımlandı ancak başlatılmadı", diff --git a/packages/pyright-internal/src/localization/package.nls.zh-cn.json b/packages/pyright-internal/src/localization/package.nls.zh-cn.json index 033f8dd1b5..1ef41046f0 100644 --- a/packages/pyright-internal/src/localization/package.nls.zh-cn.json +++ b/packages/pyright-internal/src/localization/package.nls.zh-cn.json @@ -496,7 +496,7 @@ "typeNotSpecializable": "无法专用化类型“{type}”", "typeNotSubscriptable": "类型为“{type}”的对象不可下标", "typeNotSupportBinaryOperator": "类型“{leftType}”和“{rightType}”不支持运算符“{operator}”", - "typeNotSupportBinaryOperatorBidirectional": "预期类型为 \"{expectedType}\"时,类型\"{type}\"不支持运算符\"{operator}\"", + "typeNotSupportBinaryOperatorBidirectional": "预期类型为“{expectedType}”时,类型“{leftType}”和“{rightType}”不支持运算符“{operator}”", "typeNotSupportUnaryOperator": "类型“{type}”不支持运算符“{operator}”", "typeNotSupportUnaryOperatorBidirectional": "预期类型为 \"{expectedType}\"时,类型\"{type}\"不支持运算符\"{operator}\"", "typeNotUsableWith": "\"{type}\"类型的对象不能与 “with” 一起使用,因为它未实现{method}", @@ -784,6 +784,7 @@ "typedDictFieldTypeMismatch": "类型“{type}”不可分配给项“{name}”", "typedDictFieldUndefined": "“{name}”是类型“{type}”中的未定义项", "typedDictFinalMismatch": "\"{sourceType}\"与\"{destType}\"不兼容,因为@final不匹配", + "typedDictKeyAccess": "使用 [\"{name}\"] 引用 TypedDict 中的项", "typedDictNotAllowed": "不能对实例或类检查使用 TypedDict", "unhashableType": "类型“{type}”不可哈希", "uninitializedAbstractVariable": "实例变量“{name}”在抽象基类“{classType}”中定义,但未初始化", diff --git a/packages/pyright-internal/src/localization/package.nls.zh-tw.json b/packages/pyright-internal/src/localization/package.nls.zh-tw.json index c237dd0384..5e784b9e34 100644 --- a/packages/pyright-internal/src/localization/package.nls.zh-tw.json +++ b/packages/pyright-internal/src/localization/package.nls.zh-tw.json @@ -784,6 +784,7 @@ "typedDictFieldTypeMismatch": "型別 \"{type}\" 無法指派給項目 \"{name}\"", "typedDictFieldUndefined": "\"{name}\" 是型別 \"{type}\" 中未定義的項目", "typedDictFinalMismatch": "\"{sourceType}\" 與 \"{destType}\" 不相容,因為@final 不符", + "typedDictKeyAccess": "使用 [\"{name}\"] 參考 TypedDict 中的項目", "typedDictNotAllowed": "執行個體或類別檢查無法使用 TypedDict", "unhashableType": "型別 \"{type}\" 無法雜湊", "uninitializedAbstractVariable": "執行個體變數 \"{name}\" 在抽象基底類別 \"{classType}\" 中定義,但未初始化", diff --git a/packages/pyright-internal/src/parser/parser.ts b/packages/pyright-internal/src/parser/parser.ts index 42cddc9c35..c3329099b0 100644 --- a/packages/pyright-internal/src/parser/parser.ts +++ b/packages/pyright-internal/src/parser/parser.ts @@ -4138,7 +4138,7 @@ export class Parser { if (this._consumeTokenIfOperator(OperatorType.Power)) { doubleStarExpression = this._parseExpression(/* allowUnpack */ false); } else { - keyExpression = this._parseTestOrStarExpression(/* allowAssignmentExpression */ true); + keyExpression = this._parseTestOrStarExpression(/* allowAssignmentExpression */ false); if (this._consumeTokenIfType(TokenType.Colon)) { valueExpression = this._parseTestExpression(/* allowAssignmentExpression */ false); diff --git a/packages/pyright-internal/src/tests/harness/fourslash/testState.ts b/packages/pyright-internal/src/tests/harness/fourslash/testState.ts index 7f8b8733eb..84752061b4 100644 --- a/packages/pyright-internal/src/tests/harness/fourslash/testState.ts +++ b/packages/pyright-internal/src/tests/harness/fourslash/testState.ts @@ -815,8 +815,8 @@ export class TestState { return commandResult; } - verifyWorkspaceEdit(expected: WorkspaceEdit, actual: WorkspaceEdit) { - return verifyWorkspaceEdit(expected, actual); + verifyWorkspaceEdit(expected: WorkspaceEdit, actual: WorkspaceEdit, marker?: string) { + return verifyWorkspaceEdit(expected, actual, marker); } async verifyInvokeCodeAction( diff --git a/packages/pyright-internal/src/tests/harness/fourslash/workspaceEditTestUtils.ts b/packages/pyright-internal/src/tests/harness/fourslash/workspaceEditTestUtils.ts index 6503d77201..1cfdc5ccf5 100644 --- a/packages/pyright-internal/src/tests/harness/fourslash/workspaceEditTestUtils.ts +++ b/packages/pyright-internal/src/tests/harness/fourslash/workspaceEditTestUtils.ts @@ -22,9 +22,9 @@ import { import * as debug from '../../../common/debug'; import { rangesAreEqual } from '../../../common/textRange'; -export function verifyWorkspaceEdit(expected: WorkspaceEdit, actual: WorkspaceEdit) { +export function verifyWorkspaceEdit(expected: WorkspaceEdit, actual: WorkspaceEdit, marker?: string) { if (actual.changes) { - verifyTextEditMap(expected.changes!, actual.changes); + verifyTextEditMap(expected.changes!, actual.changes, marker); } else { assert(!expected.changes); } @@ -143,11 +143,19 @@ export function verifyDocumentEdits( } } -export function verifyTextEditMap(expected: { [uri: string]: TextEdit[] }, actual: { [uri: string]: TextEdit[] }) { - assert.strictEqual(Object.entries(expected).length, Object.entries(actual).length); +export function verifyTextEditMap( + expected: { [uri: string]: TextEdit[] }, + actual: { [uri: string]: TextEdit[] }, + marker?: string +) { + assert.strictEqual( + Object.entries(expected).length, + Object.entries(actual).length, + marker === undefined ? '' : `${marker} has failed` + ); for (const key of Object.keys(expected)) { - assert(textEditsAreSame(expected[key], actual[key])); + assert(textEditsAreSame(expected[key], actual[key]), marker === undefined ? '' : `${marker} has failed`); } } diff --git a/packages/pyright-internal/src/tests/samples/assignmentExpr2.py b/packages/pyright-internal/src/tests/samples/assignmentExpr2.py index 27b4f6fd69..8c95857be9 100644 --- a/packages/pyright-internal/src/tests/samples/assignmentExpr2.py +++ b/packages/pyright-internal/src/tests/samples/assignmentExpr2.py @@ -53,3 +53,15 @@ def func2(): def func3(): # This should generate an error. yield from y := [1] + +def func4(): + # This should generate an error. + v1 = {x := 'a': 0} + + v2 = {(x := 'a'): 0} + + # This should generate an error. + v3 = {x := 'a': i for i in range(4)} + + v4 = {(x := 'a'): i for i in range(4)} + diff --git a/packages/pyright-internal/src/tests/samples/constructor13.py b/packages/pyright-internal/src/tests/samples/constructor13.py index 7e6d85d4db..85fbd8c14c 100644 --- a/packages/pyright-internal/src/tests/samples/constructor13.py +++ b/packages/pyright-internal/src/tests/samples/constructor13.py @@ -11,5 +11,7 @@ def __init__(self) -> None: val = self.method1() reveal_type(val(), expected_text="T@Foo") - def method1(self) -> type[T]: - ... + # This should generate an error. + val(1) + + def method1(self) -> type[T]: ... diff --git a/packages/pyright-internal/src/tests/samples/constructor18.py b/packages/pyright-internal/src/tests/samples/constructor18.py index 2efd205c0e..d45c95f452 100644 --- a/packages/pyright-internal/src/tests/samples/constructor18.py +++ b/packages/pyright-internal/src/tests/samples/constructor18.py @@ -11,8 +11,7 @@ _ = isinstance(dict(a=0), dict) -class ClassA: - ... +class ClassA: ... _T1 = TypeVar("_T1", bound=ClassA | str, covariant=True) @@ -24,12 +23,10 @@ def __new__(cls, *args, **kwargs) -> Self: return super().__new__(cls, *args, **kwargs) @overload - def __init__(self: "ClassB[_T1]", arg: _T1) -> None: - ... + def __init__(self, arg: _T1) -> None: ... @overload - def __init__(self: "ClassB[str]", arg: int) -> None: - ... + def __init__(self: "ClassB[str]", arg: int) -> None: ... def __init__(self, arg: int | ClassA | str) -> None: pass diff --git a/packages/pyright-internal/src/tests/samples/constructor21.py b/packages/pyright-internal/src/tests/samples/constructor21.py index 6b7b08c557..ebe6449db7 100644 --- a/packages/pyright-internal/src/tests/samples/constructor21.py +++ b/packages/pyright-internal/src/tests/samples/constructor21.py @@ -13,7 +13,7 @@ def __init__(self, a: int, b: str): def func1(cls: type[T_A]) -> T_A: - # This should generate an error + # This should generate an error. y = cls() x = cls(1, "") @@ -25,6 +25,7 @@ def func1(cls: type[T_A]) -> T_A: def func2(cls: type[_T]) -> _T: + # This should generate an error. y = cls(1, "") x = cls() diff --git a/packages/pyright-internal/src/tests/samples/constructor6.py b/packages/pyright-internal/src/tests/samples/constructor6.py index b4192bab54..04f20db52b 100644 --- a/packages/pyright-internal/src/tests/samples/constructor6.py +++ b/packages/pyright-internal/src/tests/samples/constructor6.py @@ -9,26 +9,21 @@ class TextField(Generic[_T]): @overload - def __init__(self: "TextField[str]", *, null: Literal[False] = ...) -> None: - ... + def __init__(self: "TextField[str]", *, null: Literal[False] = ...) -> None: ... @overload def __init__( self: "TextField[Optional[str]]", *, null: Literal[True] = ..., - ) -> None: - ... + ) -> None: ... @overload - def __init__(self, *, null: bool = ...) -> None: - ... + def __init__(self, *, null: bool = ...) -> None: ... - def __init__(self, *, null: bool = ...) -> None: - ... + def __init__(self, *, null: bool = ...) -> None: ... - def __get__(self: "TextField[_T]", instance: Any, owner: Any) -> _T: - ... + def __get__(self: "TextField[_T]", instance: Any, owner: Any) -> _T: ... def foo(a: bool): @@ -37,8 +32,7 @@ def foo(a: bool): reveal_type(TextField(null=a), expected_text="TextField[Unknown]") -class Model: - ... +class Model: ... _T1 = TypeVar("_T1", bound="Optional[Model]") @@ -49,17 +43,14 @@ class ForeignKey(Generic[_T1]): @overload def __init__( self: "ForeignKey[_T2]", to: Type[_T2], *, null: Literal[False] = ... - ) -> None: - ... + ) -> None: ... @overload def __init__( self: "ForeignKey[Optional[_T2]]", to: Type[_T2], *, null: Literal[True] - ) -> None: - ... + ) -> None: ... - def __init__(self, to: Type[_T2], *, null: bool = False) -> None: - ... + def __init__(self, to: Type[_T2], *, null: bool = False) -> None: ... class Author(Model): @@ -68,3 +59,29 @@ class Author(Model): reveal_type(ForeignKey(Author, null=False), expected_text="ForeignKey[Author]") reveal_type(ForeignKey(Author, null=True), expected_text="ForeignKey[Author | None]") + + +_T3 = TypeVar("_T3") +_T4 = TypeVar("_T4") +_S1 = TypeVar("_S1") +_S2 = TypeVar("_S2") + + +class Class1(Generic[_T3, _T4]): + def __init__(self: "Class1[_S1, _S2]", value1: _S1, value2: _S2) -> None: ... + + +reveal_type(Class1(0, ""), expected_text="Class1[int, str]") + + +class Class2(Generic[_T3, _T4]): + def __init__(self: "Class2[_S2, _S1]", value1: _S1, value2: _S2) -> None: ... + + +reveal_type(Class2(0, ""), expected_text="Class2[str, int]") + + +class Class3(Generic[_T3, _T4]): + # This should generate an error because class-scoped TypeVars are not + # allowed in the "self" type annotation for an __init__ method. + def __init__(self: "Class3[_T3, _T4]", value1: _T3, value2: _T4) -> None: ... diff --git a/packages/pyright-internal/src/tests/samples/constructor8.py b/packages/pyright-internal/src/tests/samples/constructorCallable1.py similarity index 81% rename from packages/pyright-internal/src/tests/samples/constructor8.py rename to packages/pyright-internal/src/tests/samples/constructorCallable1.py index 1f036d8cca..078086726d 100644 --- a/packages/pyright-internal/src/tests/samples/constructor8.py +++ b/packages/pyright-internal/src/tests/samples/constructorCallable1.py @@ -20,13 +20,11 @@ R = TypeVar("R") -def func1(callback: Callable[[T1], T2], val: T1) -> T2: - ... +def func1(callback: Callable[[T1], T2], val: T1) -> T2: ... class A(Generic[T1]): - def __new__(cls, x: T1) -> "A[T1]": - ... + def __new__(cls, x: T1) -> "A[T1]": ... a1 = func1(A[float], 3.4) @@ -41,15 +39,12 @@ def __new__(cls, x: T1) -> "A[T1]": class B(Generic[T1]): @overload - def __new__(cls, x: int, y: Literal[True]) -> "B[None]": - ... + def __new__(cls, x: int, y: Literal[True]) -> "B[None]": ... @overload - def __new__(cls, x: T1, y: bool = ...) -> "B[T1]": - ... + def __new__(cls, x: T1, y: bool = ...) -> "B[T1]": ... - def __new__(cls, x: Union[T1, int], y: bool = False) -> "B[Any]": - ... + def __new__(cls, x: Union[T1, int], y: bool = False) -> "B[Any]": ... b1 = func1(B[int], 3) @@ -69,8 +64,7 @@ def __new__(cls, x: Union[T1, int], y: bool = False) -> "B[Any]": class C(Generic[T1]): - def __init__(self: "C[T1]", x: T1) -> None: - ... + def __init__(self, x: T1) -> None: ... c1 = func1(C[float], 3.4) @@ -85,15 +79,12 @@ def __init__(self: "C[T1]", x: T1) -> None: class D(Generic[T1]): @overload - def __init__(self: "D[None]", x: int, y: Literal[True]) -> None: - ... + def __init__(self: "D[None]", x: int, y: Literal[True]) -> None: ... @overload - def __init__(self: "D[T1]", x: T1, y: bool = ...) -> None: - ... + def __init__(self, x: T1, y: bool = ...) -> None: ... - def __init__(self, x: Any, y: bool = False) -> None: - ... + def __init__(self, x: Any, y: bool = False) -> None: ... d1 = func1(D[int], 3) @@ -120,8 +111,7 @@ class E(Generic[T1]): e1: Callable[[int], E[int]] = E -def func2(x: T1) -> E[T1]: - ... +def func2(x: T1) -> E[T1]: ... e2: Callable[[int], E[int]] = func2 diff --git a/packages/pyright-internal/src/tests/samples/constructorCallable2.py b/packages/pyright-internal/src/tests/samples/constructorCallable2.py new file mode 100644 index 0000000000..b3e2cd8b2f --- /dev/null +++ b/packages/pyright-internal/src/tests/samples/constructorCallable2.py @@ -0,0 +1,142 @@ +# This sample tests the case where a constructor is converted to +# a callable. + + +from typing import ( + Any, + Callable, + Generic, + NoReturn, + ParamSpec, + Self, + TypeVar, + overload, + reveal_type, +) + +P = ParamSpec("P") +R = TypeVar("R") +T = TypeVar("T") + + +def accepts_callable(cb: Callable[P, R]) -> Callable[P, R]: + return cb + + +class Class1: + def __init__(self, x: int) -> None: + pass + + +r1 = accepts_callable(Class1) +reveal_type(r1, expected_text="(x: int) -> Class1") +reveal_type(r1(1), expected_text="Class1") + + +class Class2: + pass + + +r2 = accepts_callable(Class2) +reveal_type(r2, expected_text="() -> Class2") +reveal_type(r2(), expected_text="Class2") + + +class Class3: + def __new__(cls, *args, **kwargs) -> Self: ... + def __init__(self, x: int) -> None: ... + + +r3 = accepts_callable(Class3) +reveal_type(r3, expected_text="(x: int) -> Class3") +reveal_type(r3(3), expected_text="Class3") + + +class Class4: + def __new__(cls, x: int) -> int: ... + + +r4 = accepts_callable(Class4) +reveal_type(r4, expected_text="(x: int) -> int") +reveal_type(r4(1), expected_text="int") + + +class Meta1(type): + def __call__(cls, *args: Any, **kwargs: Any) -> NoReturn: + raise NotImplementedError("Class not constructable") + + +class Class5(metaclass=Meta1): + def __new__(cls, *args: Any, **kwargs: Any) -> Self: + return super().__new__(cls) + + +r5 = accepts_callable(Class5) +reveal_type(r5, expected_text="(*args: Any, **kwargs: Any) -> NoReturn") + + +class Class6Proxy: ... + + +class Class6: + def __new__(cls) -> Class6Proxy: + return Class6Proxy.__new__(cls) + + def __init__(self, x: int) -> None: + pass + + +r6 = accepts_callable(Class6) +reveal_type(r6, expected_text="() -> Class6Proxy") +reveal_type(r6(), expected_text="Class6Proxy") + + +class Class6_2: + def __new__(cls) -> Any: + return super().__new__(cls) + + def __init__(self, x: int) -> None: + pass + + +r6_2 = accepts_callable(Class6_2) +reveal_type(r6_2, expected_text="() -> Any") +reveal_type(r6_2(), expected_text="Any") + + +class Class7(Generic[T]): + @overload + def __init__(self: "Class7[int]", x: int) -> None: ... + @overload + def __init__(self: "Class7[str]", x: str) -> None: ... + def __init__(self, x: int | str) -> None: + pass + + +r7 = accepts_callable(Class7) +reveal_type( + r7, expected_text="Overload[(x: int) -> Class7[int], (x: str) -> Class7[str]]" +) + +reveal_type(r7(0), expected_text="Class7[int]") +reveal_type(r7(""), expected_text="Class7[str]") + + +class Class8(Generic[T]): + def __new__(cls, x: T, y: list[T]) -> Self: + return super().__new__(cls) + + +r8 = accepts_callable(Class8) +reveal_type(r8, expected_text="(x: T@Class8, y: list[T@Class8]) -> Class8[T@Class8]") +reveal_type(r8("", [""]), expected_text="Class8[str]") + + +class Class9: + def __init__(self, x: list[T], y: list[T]) -> None: + pass + + +r9 = accepts_callable(Class9) +reveal_type(r9, expected_text="(x: list[T@__init__], y: list[T@__init__]) -> Class9") +reveal_type(r9([""], [""]), expected_text="Class9") diff --git a/packages/pyright-internal/src/tests/samples/dataclass4.py b/packages/pyright-internal/src/tests/samples/dataclass4.py index 200d56baec..31640b1ff8 100644 --- a/packages/pyright-internal/src/tests/samples/dataclass4.py +++ b/packages/pyright-internal/src/tests/samples/dataclass4.py @@ -6,16 +6,13 @@ from dataclasses import dataclass, field -class C1: - ... +class C1: ... -class C2: - ... +class C2: ... -class C3: - ... +class C3: ... @dataclass @@ -74,6 +71,9 @@ class DC6: @dataclass class DC7(DC6): + # This should generate an error because it is overriding + # a field with a default value, but it doesn't have a + # default value. a: int # This should generate an error because the default @@ -88,6 +88,9 @@ class DC8: @dataclass class DC9(DC8): + # This should generate an error because it is overriding + # a field with a default value, but it doesn't have a + # default value. a: int # This should generate an error because the default diff --git a/packages/pyright-internal/src/tests/samples/dataclass6.py b/packages/pyright-internal/src/tests/samples/dataclass6.py index 157be6b6af..c2a96330d1 100644 --- a/packages/pyright-internal/src/tests/samples/dataclass6.py +++ b/packages/pyright-internal/src/tests/samples/dataclass6.py @@ -23,7 +23,7 @@ def __post_init__(self): @dataclass class ChildA(ParentA): - prop_2: str + prop_2: str = "bye" test = ChildA(prop_2="test", prop_4="hi") diff --git a/packages/pyright-internal/src/tests/samples/loop16.py b/packages/pyright-internal/src/tests/samples/loop16.py index d697908612..4ba894e854 100644 --- a/packages/pyright-internal/src/tests/samples/loop16.py +++ b/packages/pyright-internal/src/tests/samples/loop16.py @@ -273,16 +273,16 @@ def get_ipv4(): continue elif ip1 == 13 and ip2 == 107 and ip3 == 6 and ip4 == 152: continue - elif ip1 == 13 and ip2 == 107 and ip3 == 18 and ip4 == 10: - continue - elif ip1 == 13 and ip2 == 107 and ip3 == 128 and ip4 == 0: - continue - elif ip1 == 23 and ip2 == 103 and ip3 == 160 and ip4 == 0: - continue - elif ip1 == 40 and ip2 == 96 and ip3 == 0 and ip4 == 0: - continue - elif ip1 == 40 and ip2 == 104 and ip3 == 0 and ip4 == 0: - continue + # elif ip1 == 13 and ip2 == 107 and ip3 == 18 and ip4 == 10: + # continue + # elif ip1 == 13 and ip2 == 107 and ip3 == 128 and ip4 == 0: + # continue + # elif ip1 == 23 and ip2 == 103 and ip3 == 160 and ip4 == 0: + # continue + # elif ip1 == 40 and ip2 == 96 and ip3 == 0 and ip4 == 0: + # continue + # elif ip1 == 40 and ip2 == 104 and ip3 == 0 and ip4 == 0: + # continue # elif ip1 == 52 and ip2 == 96 and ip3 == 0 and ip4 == 0: # continue # elif ip1 == 131 and ip2 == 253 and ip3 == 33 and ip4 == 215: diff --git a/packages/pyright-internal/src/tests/samples/memberAccess6.py b/packages/pyright-internal/src/tests/samples/memberAccess6.py index c97c6bc36d..ce934fd328 100644 --- a/packages/pyright-internal/src/tests/samples/memberAccess6.py +++ b/packages/pyright-internal/src/tests/samples/memberAccess6.py @@ -14,19 +14,17 @@ class ParentA: class Column(Generic[_T]): - def __init__(self: "Column[_T]", type: type[_T]) -> None: - ... + def __init__(self, type: type[_T]) -> None: ... @overload - def __get__(self: "Column[_T]", instance: None, type: Any) -> "Column[_T]": - ... + def __get__(self: "Column[_T]", instance: None, type: Any) -> "Column[_T]": ... @overload - def __get__(self: "Column[_T]", instance: ParentA, type: Any) -> _T: - ... + def __get__(self: "Column[_T]", instance: ParentA, type: Any) -> _T: ... - def __get__(self, instance: ParentA | None, type: Any) -> _T | None | "Column[_T]": - ... + def __get__( + self, instance: ParentA | None, type: Any + ) -> _T | None | "Column[_T]": ... class ChildA(ParentA): diff --git a/packages/pyright-internal/src/tests/samples/metaclass7.py b/packages/pyright-internal/src/tests/samples/metaclass7.py index 85fab596eb..dd39492275 100644 --- a/packages/pyright-internal/src/tests/samples/metaclass7.py +++ b/packages/pyright-internal/src/tests/samples/metaclass7.py @@ -16,7 +16,7 @@ def __new__(cls, *args, **kwargs): v1 = Class1() -reveal_type(v1, expected_text="Class1") +reveal_type(v1, expected_text="NoReturn") class MetaClass2(type): diff --git a/packages/pyright-internal/src/tests/samples/paramSpec10.py b/packages/pyright-internal/src/tests/samples/paramSpec10.py index 90f611e07a..3cb6447ce5 100644 --- a/packages/pyright-internal/src/tests/samples/paramSpec10.py +++ b/packages/pyright-internal/src/tests/samples/paramSpec10.py @@ -29,17 +29,14 @@ def __init__(self): self._lock = RLock() @with_lock - def test_1(self, param1: int) -> str: - ... + def test_1(self, param1: int) -> str: ... @with_lock - def test_2(self) -> str: - ... + def test_2(self) -> str: ... @with_lock -def test_3(cls: MyClass, param1: int) -> str: - ... +def test_3(cls: MyClass, param1: int) -> str: ... testClass = MyClass() @@ -54,4 +51,4 @@ def test_3(cls: MyClass, param1: int) -> str: reveal_type(res3, expected_text="str") res4: Callable[[MyClass, int], str] = with_lock(test_3) -reveal_type(res4, expected_text="(MyClass, param1: int) -> str") +reveal_type(res4, expected_text="(MyClass, int) -> str") diff --git a/packages/pyright-internal/src/tests/samples/paramSpec3.py b/packages/pyright-internal/src/tests/samples/paramSpec3.py index e2bceea0da..b6ab5e3f13 100644 --- a/packages/pyright-internal/src/tests/samples/paramSpec3.py +++ b/packages/pyright-internal/src/tests/samples/paramSpec3.py @@ -35,13 +35,11 @@ async def func2(): @overload -def func3(x: int) -> None: - ... +def func3(x: int) -> None: ... @overload -def func3(x: str) -> str: - ... +def func3(x: str) -> str: ... def func3(x: int | str) -> str | None: @@ -75,8 +73,7 @@ def decorator2(f: Callable[P, R]) -> Callable[P, R]: def func5(f: Callable[[], list[T1]]) -> Callable[[list[T2]], list[T1 | T2]]: - def inner(res: list[T2]) -> list[T1 | T2]: - ... + def inner(res: list[T2], /) -> list[T1 | T2]: ... return decorator2(inner) @@ -87,3 +84,26 @@ def inner(*args: P.args, **kwargs: P.kwargs) -> None: fn(*args, **kwargs) return inner + + +class Callback1: + def __call__(self, x: int | str, y: int = 3) -> None: ... + + +class Callback2: + def __call__(self, x: int, /) -> None: ... + + +class Callback3: + def __call__(self, *args, **kwargs) -> None: ... + + +def func7(f1: Callable[P, R], f2: Callable[P, R]) -> Callable[P, R]: ... + + +def func8(cb1: Callback1, cb2: Callback2, cb3: Callback3): + v1 = func7(cb1, cb2) + reveal_type(v1, expected_text="(x: int, /) -> None") + + v2 = func7(cb1, cb3) + reveal_type(v2, expected_text="(x: int | str, y: int = 3) -> None") diff --git a/packages/pyright-internal/src/tests/samples/property18.py b/packages/pyright-internal/src/tests/samples/property18.py new file mode 100644 index 0000000000..8d5e200375 --- /dev/null +++ b/packages/pyright-internal/src/tests/samples/property18.py @@ -0,0 +1,21 @@ +# This sample tests the case where a @property decorator is applied to +# a method that has been previously decorated. + +from typing import ParamSpec, TypeVar, Callable + +P = ParamSpec("P") +R = TypeVar("R") + + +def deco1(func: Callable[P, R]) -> Callable[P, R]: ... + + +class ClassA: + @property + @deco1 + def prop(self) -> int: + return 1 + + +a = ClassA() +reveal_type(a.prop, expected_text="int") diff --git a/packages/pyright-internal/src/tests/samples/solver24.py b/packages/pyright-internal/src/tests/samples/solver24.py index d1cc73e4be..1f6881ef70 100644 --- a/packages/pyright-internal/src/tests/samples/solver24.py +++ b/packages/pyright-internal/src/tests/samples/solver24.py @@ -6,6 +6,7 @@ V = TypeVar("V") V_co = TypeVar("V_co", covariant=True) +T = TypeVar("T") U = TypeVar("U") @@ -30,24 +31,28 @@ def func1(a: ClassA[V], b: ClassA[U], c: bool) -> ClassB[V | U]: return r -class ClassC(Generic[AnyStr]): - ... +class ClassC(Generic[AnyStr]): ... -class ClassD(Iterator[ClassC[AnyStr]], Protocol): - ... +class ClassD(Iterator[ClassC[AnyStr]], Protocol): ... GenericPath: TypeAlias = AnyStr | PathLike[AnyStr] -def func2(iter: Iterable[object]) -> bool: - ... +def func2(iter: Iterable[object]) -> bool: ... -def func3(path: GenericPath[AnyStr]) -> ClassD[AnyStr]: - ... +def func3(path: GenericPath[AnyStr]) -> ClassD[AnyStr]: ... def func4(val: str): func2(func3(val)) + + +def func5(a: dict[T, U], b: list[T | U]): + pass + + +def func6(a: dict[str, int], b: list[str | int]): + func5(a, b) diff --git a/packages/pyright-internal/src/tests/samples/typeNarrowingIn1.py b/packages/pyright-internal/src/tests/samples/typeNarrowingIn1.py index b2db7e0932..86d1cad521 100644 --- a/packages/pyright-internal/src/tests/samples/typeNarrowingIn1.py +++ b/packages/pyright-internal/src/tests/samples/typeNarrowingIn1.py @@ -1,19 +1,16 @@ # This sample tests type narrowing for the "in" operator. -from typing import Literal, TypedDict +from typing import Literal, TypeVar, TypedDict import random -def verify_str(p: str) -> None: - ... +def verify_str(p: str) -> None: ... -def verify_int(p: int) -> None: - ... +def verify_int(p: int) -> None: ... -def verify_none(p: None) -> None: - ... +def verify_none(p: None) -> None: ... x: str | None @@ -153,3 +150,13 @@ def func11(x: dict[str, str]): reveal_type(x, expected_text="TD1 | TD2") else: reveal_type(x, expected_text="dict[str, str]") + + +T1 = TypeVar("T1", TD1, TD2) + + +def func12(v: T1): + if "x" in v: + reveal_type(v, expected_text="TD1*") + else: + reveal_type(v, expected_text="TD2*") diff --git a/packages/pyright-internal/src/tests/samples/typeNarrowingTupleLength1.py b/packages/pyright-internal/src/tests/samples/typeNarrowingTupleLength1.py index 922c39d387..d5d5be82de 100644 --- a/packages/pyright-internal/src/tests/samples/typeNarrowingTupleLength1.py +++ b/packages/pyright-internal/src/tests/samples/typeNarrowingTupleLength1.py @@ -49,11 +49,13 @@ def func4(val: _T1 | _T2) -> _T1 | _T2: def func5( - val: tuple[int, ...] - | tuple[str] - | tuple[str, str, str] - | tuple[int, *tuple[str, ...], str] - | tuple[int, *tuple[float, ...]], + val: ( + tuple[int, ...] + | tuple[str] + | tuple[str, str, str] + | tuple[int, *tuple[str, ...], str] + | tuple[int, *tuple[float, ...]] + ), length: Literal[2], ): if len(val) == length: @@ -65,3 +67,66 @@ def func5( val, expected_text="tuple[int, ...] | tuple[str] | tuple[str, str, str] | tuple[int, *tuple[str, ...], str] | tuple[int, *tuple[float, ...]]", ) + + +def func10(t: tuple[()] | tuple[int] | tuple[int, int] | tuple[int, int, int]): + if len(t) >= 2: + reveal_type(t, expected_text="tuple[int, int] | tuple[int, int, int]") + else: + reveal_type(t, expected_text="tuple[()] | tuple[int]") + + +def func11(t: tuple[()] | tuple[int] | tuple[int, int] | tuple[int, int, int]): + if len(t) > 1: + reveal_type(t, expected_text="tuple[int, int] | tuple[int, int, int]") + else: + reveal_type(t, expected_text="tuple[()] | tuple[int]") + + +def func12(t: tuple[()] | tuple[int] | tuple[int, int]): + if len(t) >= 0: + reveal_type(t, expected_text="tuple[()] | tuple[int] | tuple[int, int]") + else: + reveal_type(t, expected_text="Never") + + +def func20(t: tuple[int, ...]): + if len(t) >= 2: + reveal_type(t, expected_text="tuple[int, int, *tuple[int, ...]]") + else: + reveal_type(t, expected_text="tuple[()] | tuple[int]") + + +def func21(t: tuple[int, ...]): + if len(t) > 0: + reveal_type(t, expected_text="tuple[int, *tuple[int, ...]]") + else: + reveal_type(t, expected_text="tuple[()]") + + +def func22(t: tuple[str, *tuple[int, ...], str]): + if len(t) < 3: + reveal_type(t, expected_text="tuple[str, str]") + else: + reveal_type(t, expected_text="tuple[str, int, *tuple[int, ...], str]") + + +def func23(t: tuple[str, *tuple[int, ...], str]): + if len(t) <= 3: + reveal_type(t, expected_text="tuple[str, str] | tuple[str, int, str]") + else: + reveal_type(t, expected_text="tuple[str, int, int, *tuple[int, ...], str]") + + +def func24(t: tuple[str, *tuple[int, ...], str]): + if len(t) <= 34: + reveal_type(t, expected_text="tuple[str, *tuple[int, ...], str]") + else: + reveal_type(t, expected_text="tuple[str, *tuple[int, ...], str]") + + +def func25(t: tuple[str, *tuple[int, ...], str]): + if len(t) < 2: + reveal_type(t, expected_text="Never") + else: + reveal_type(t, expected_text="tuple[str, *tuple[int, ...], str]") diff --git a/packages/pyright-internal/src/tests/samples/typeParams1.py b/packages/pyright-internal/src/tests/samples/typeParams1.py index f3327700ba..1009fee8a6 100644 --- a/packages/pyright-internal/src/tests/samples/typeParams1.py +++ b/packages/pyright-internal/src/tests/samples/typeParams1.py @@ -3,58 +3,64 @@ T1 = 0 -class ClassA[T1]: - ... -def func1[T1](): - ... +class ClassA[T1]: ... + + +def func1[T1](): ... T2: str -class ClassB[T2]: - ... -def func2[T2](): - ... +class ClassB[T2]: ... + + +def func2[T2](): ... # This should generate an error because T3 is duplicated. -class ClassC[T3, S1, T3]: - ... +class ClassC[T3, S1, T3]: ... # This should generate an error because T3 is duplicated. -def func3[T3, S1, T3](): - ... +def func3[T3, S1, T3](): ... + + +def func4[T4](T4: int): ... -def func4[T4](T4: int): - ... def func5[T5](a: int): # This should generate an error because T5 is already in use. - class ClassA[T5]: - ... + class ClassA[T5]: ... # This should generate an error because T5 is already in use. - def inner_func1[T5](): - ... + def inner_func1[T5](): ... + def func6[T6](T7: int): - class ClassA[T7]: - ... + class ClassA[T7]: ... - def inner_func1[T7](): - ... + def inner_func1[T7](): ... global T2 class ClassB[T2]: global T2 - class ClassC[T3]: T3 = 4 T3 = 4 + +def func7[T8: ForwardRefClass[str], T9: "ForwardRefClass[int]"](): + pass + + +def func8[T10: (ForwardRefClass[str], "ForwardRefClass[int]")](): + pass + + +class ForwardRefClass[T]: + pass diff --git a/packages/pyright-internal/src/tests/typeEvaluator1.test.ts b/packages/pyright-internal/src/tests/typeEvaluator1.test.ts index ac9a6ae99c..dd04e99c8e 100644 --- a/packages/pyright-internal/src/tests/typeEvaluator1.test.ts +++ b/packages/pyright-internal/src/tests/typeEvaluator1.test.ts @@ -1189,6 +1189,12 @@ test('Property17', () => { TestUtils.validateResults(analysisResults, 0); }); +test('Property18', () => { + const analysisResults = TestUtils.typeAnalyzeSampleFiles(['property18.py']); + + TestUtils.validateResults(analysisResults, 0); +}); + test('Operator1', () => { const analysisResults = TestUtils.typeAnalyzeSampleFiles(['operator1.py']); diff --git a/packages/pyright-internal/src/tests/typeEvaluator3.test.ts b/packages/pyright-internal/src/tests/typeEvaluator3.test.ts index 76de897f1a..8fbb908515 100644 --- a/packages/pyright-internal/src/tests/typeEvaluator3.test.ts +++ b/packages/pyright-internal/src/tests/typeEvaluator3.test.ts @@ -1536,7 +1536,7 @@ test('Constructor5', () => { test('Constructor6', () => { const analysisResults = TestUtils.typeAnalyzeSampleFiles(['constructor6.py']); - TestUtils.validateResults(analysisResults, 0); + TestUtils.validateResults(analysisResults, 1); }); test('Constructor7', () => { @@ -1545,12 +1545,6 @@ test('Constructor7', () => { TestUtils.validateResults(analysisResults, 0); }); -test('Constructor8', () => { - const analysisResults = TestUtils.typeAnalyzeSampleFiles(['constructor8.py']); - - TestUtils.validateResults(analysisResults, 4); -}); - test('Constructor9', () => { const analysisResults = TestUtils.typeAnalyzeSampleFiles(['constructor9.py']); @@ -1578,7 +1572,7 @@ test('Constructor12', () => { test('Constructor13', () => { const analysisResults = TestUtils.typeAnalyzeSampleFiles(['constructor13.py']); - TestUtils.validateResults(analysisResults, 0); + TestUtils.validateResults(analysisResults, 1); }); test('Constructor14', () => { @@ -1626,7 +1620,7 @@ test('Constructor20', () => { test('Constructor21', () => { const analysisResults = TestUtils.typeAnalyzeSampleFiles(['constructor21.py']); - TestUtils.validateResults(analysisResults, 1); + TestUtils.validateResults(analysisResults, 2); }); test('Constructor22', () => { @@ -1683,6 +1677,18 @@ test('Constructor29', () => { TestUtils.validateResults(analysisResults, 0); }); +test('ConstructorCallable1', () => { + const analysisResults = TestUtils.typeAnalyzeSampleFiles(['constructorCallable1.py']); + + TestUtils.validateResults(analysisResults, 4); +}); + +test('ConstructorCallable2', () => { + const analysisResults = TestUtils.typeAnalyzeSampleFiles(['constructorCallable2.py']); + + TestUtils.validateResults(analysisResults, 0); +}); + test('InconsistentConstructor1', () => { const configOptions = new ConfigOptions(Uri.empty()); diff --git a/packages/pyright-internal/src/tests/typeEvaluator4.test.ts b/packages/pyright-internal/src/tests/typeEvaluator4.test.ts index 2a9bf7a771..420af3d03e 100644 --- a/packages/pyright-internal/src/tests/typeEvaluator4.test.ts +++ b/packages/pyright-internal/src/tests/typeEvaluator4.test.ts @@ -112,7 +112,7 @@ test('AssignmentExpr1', () => { test('AssignmentExpr2', () => { const analysisResults = TestUtils.typeAnalyzeSampleFiles(['assignmentExpr2.py']); - TestUtils.validateResults(analysisResults, 6); + TestUtils.validateResults(analysisResults, 8); }); test('AssignmentExpr3', () => { @@ -607,7 +607,7 @@ test('DataClass3', () => { test('DataClass4', () => { const analysisResults = TestUtils.typeAnalyzeSampleFiles(['dataclass4.py']); - TestUtils.validateResults(analysisResults, 4); + TestUtils.validateResults(analysisResults, 6); }); test('DataClass5', () => { diff --git a/packages/pyright/package-lock.json b/packages/pyright/package-lock.json index 2808cf1b61..a026b08d6c 100644 --- a/packages/pyright/package-lock.json +++ b/packages/pyright/package-lock.json @@ -1,12 +1,12 @@ { "name": "basedpyright", - "version": "1.1.358", + "version": "1.1.359", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "basedpyright", - "version": "1.1.358", + "version": "1.1.359", "license": "MIT", "bin": { "pyright": "index.js", diff --git a/packages/pyright/package.json b/packages/pyright/package.json index e6b650f3ba..8f875f47fe 100644 --- a/packages/pyright/package.json +++ b/packages/pyright/package.json @@ -2,7 +2,7 @@ "name": "basedpyright", "displayName": "basedpyright", "description": "a pyright fork with various type checking improvements, improved vscode support and pylance features built into the language server", - "version": "1.1.358", + "version": "1.1.359", "license": "MIT", "author": { "name": "detachhead" diff --git a/packages/vscode-pyright/package-lock.json b/packages/vscode-pyright/package-lock.json index 8f53f32a73..f266e32883 100644 --- a/packages/vscode-pyright/package-lock.json +++ b/packages/vscode-pyright/package-lock.json @@ -1,12 +1,12 @@ { "name": "vscode-pyright", - "version": "1.1.358", + "version": "1.1.359", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "vscode-pyright", - "version": "1.1.358", + "version": "1.1.359", "license": "MIT", "dependencies": { "@vscode/python-extension": "^1.0.5", diff --git a/packages/vscode-pyright/package.json b/packages/vscode-pyright/package.json index d71207c4a5..aece2daa96 100644 --- a/packages/vscode-pyright/package.json +++ b/packages/vscode-pyright/package.json @@ -2,7 +2,7 @@ "name": "vscode-pyright", "displayName": "BasedPyright", "description": "VS Code static type checking for Python (but based)", - "version": "1.1.358", + "version": "1.1.359", "private": true, "license": "MIT", "author": {