Skip to content

Commit

Permalink
Merge tag '1.1.359' into merge-1.1.359
Browse files Browse the repository at this point in the history
# Conflicts:
#	packages/pyright-internal/package-lock.json
#	packages/pyright-internal/package.json
#	packages/pyright/package-lock.json
#	packages/pyright/package.json
#	packages/vscode-pyright/package.json
  • Loading branch information
DetachHead committed Apr 17, 2024
2 parents 7f7b380 + cc3467f commit 85963c4
Show file tree
Hide file tree
Showing 70 changed files with 1,266 additions and 1,023 deletions.
2 changes: 1 addition & 1 deletion docs/type-concepts-advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"packages": [
"packages/*"
],
"version": "1.1.358",
"version": "1.1.359",
"command": {
"version": {
"push": false,
Expand Down
428 changes: 12 additions & 416 deletions packages/pyright-internal/package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions packages/pyright-internal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand All @@ -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",
Expand Down
23 changes: 23 additions & 0 deletions packages/pyright-internal/src/analyzer/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3148,9 +3148,32 @@ export class Binder extends ParseTreeWalker {

// Look for "X is Y" or "X is not Y".
// Look for X == <literal> or X != <literal>
// Look for len(X) == <literal> or len(X) != <literal>
return isLeftNarrowing;
}

// Look for len(X) < <literal>, len(X) <= <literal>, len(X) > <literal>, len(X) >= <literal>.
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 "<string> in Y" or "<string> not in Y".
if (expression.operator === OperatorType.In || expression.operator === OperatorType.NotIn) {
if (
Expand Down
43 changes: 30 additions & 13 deletions packages/pyright-internal/src/analyzer/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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);
}
Expand Down Expand Up @@ -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,
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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)) {
Expand Down
58 changes: 35 additions & 23 deletions packages/pyright-internal/src/analyzer/constraintSolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand Down
Loading

0 comments on commit 85963c4

Please sign in to comment.