Skip to content

Commit

Permalink
Merge branch 'main' into pull-pylance-with-pyright-1.1.392-20250115-2…
Browse files Browse the repository at this point in the history
…10905
  • Loading branch information
heejaechang authored Jan 15, 2025
2 parents 4128a04 + 10045a2 commit b81f655
Show file tree
Hide file tree
Showing 28 changed files with 281 additions and 185 deletions.
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.391",
"version": "1.1.392",
"command": {
"version": {
"push": false,
Expand Down
4 changes: 2 additions & 2 deletions packages/pyright-internal/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion 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.391",
"version": "1.1.392",
"license": "MIT",
"private": true,
"files": [
Expand Down
25 changes: 5 additions & 20 deletions packages/pyright-internal/src/analyzer/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5892,34 +5892,18 @@ export class Checker extends ParseTreeWalker {

if (isFunction(overriddenType) || isOverloaded(overriddenType)) {
const diagAddendum = new DiagnosticAddendum();
let overrideFunction: FunctionType | undefined;

if (isFunction(overrideType)) {
overrideFunction = overrideType;
} else if (isOverloaded(overrideType)) {
// Use the last overload.
const impl = OverloadedType.getImplementation(overrideType);

// If the last overload isn't an implementation, skip the check for this symbol.
if (!impl || !isFunction(impl)) {
return;
}

overrideFunction = impl;
}

if (overrideFunction) {
if (isFunction(overrideType) || isOverloaded(overrideType)) {
if (
!this._evaluator.validateOverrideMethod(
overriddenType,
overrideFunction,
overrideType,
/* baseClass */ undefined,
diagAddendum,
/* enforceParamNameMatch */ true
)
) {
const decl = overrideFunction.shared.declaration;
if (decl && decl.type === DeclarationType.Function) {
if (overrideDecl && overrideDecl.type === DeclarationType.Function) {
diag = this._evaluator.addDiagnostic(
DiagnosticRule.reportIncompatibleMethodOverride,
LocMessage.baseClassMethodTypeIncompatible().format({
Expand Down Expand Up @@ -6635,7 +6619,7 @@ export class Checker extends ParseTreeWalker {
selfSpecializeClass(childClassType, { useBoundTypeVars: true })
);

const baseType = partiallySpecializeType(
let baseType = partiallySpecializeType(
this._evaluator.getEffectiveTypeOfSymbol(baseClassAndSymbol.symbol),
baseClass,
this._evaluator.getTypeClassType(),
Expand All @@ -6651,6 +6635,7 @@ export class Checker extends ParseTreeWalker {

if (childClassType.shared.typeVarScopeId) {
overrideType = makeTypeVarsBound(overrideType, [childClassType.shared.typeVarScopeId]);
baseType = makeTypeVarsBound(baseType, [childClassType.shared.typeVarScopeId]);
}

if (isFunction(baseType) || isOverloaded(baseType)) {
Expand Down
24 changes: 14 additions & 10 deletions packages/pyright-internal/src/analyzer/constructors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,16 +423,20 @@ function validateNewMethod(

const constraints = new ConstraintTracker();

const callResult = evaluator.useSpeculativeMode(useSpeculativeModeForArgs ? errorNode : undefined, () => {
return evaluator.validateCallArgs(
errorNode,
argList,
newMethodTypeResult,
constraints,
skipUnknownArgCheck,
inferenceContext
);
});
const callResult = evaluator.useSpeculativeMode(
useSpeculativeModeForArgs ? errorNode : undefined,
() => {
return evaluator.validateCallArgs(
errorNode,
argList,
newMethodTypeResult,
constraints,
skipUnknownArgCheck,
inferenceContext
);
},
{ dependentType: newMethodTypeResult.type }
);

if (callResult.isTypeIncomplete) {
isTypeIncomplete = true;
Expand Down
2 changes: 1 addition & 1 deletion packages/pyright-internal/src/analyzer/typeCacheUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export interface SpeculativeModeOptions {
// a context is popped off the stack, all of the speculative type cache
// entries that were created within that context are removed from the
// corresponding type caches because they are no longer valid.
// Each type context also contains a map of "speculative types" that are
// The tracker also also contains a map of "speculative types" that are
// contextually evaluated based on an "expected type" and potentially
// one or more "dependent types". The "expected type" applies in cases
// where the speculative root node is being evaluated with bidirectional
Expand Down
106 changes: 65 additions & 41 deletions packages/pyright-internal/src/analyzer/typeEvaluator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2761,13 +2761,7 @@ export function createTypeEvaluator(
);

if (baseType && isClassInstance(baseType)) {
const setItemType = getBoundMagicMethod(baseType, '__setitem__');
if (setItemType && isFunction(setItemType) && setItemType.shared.parameters.length >= 2) {
const paramType = FunctionType.getParamType(setItemType, 1);
if (!isAnyOrUnknown(paramType)) {
return paramType;
}
} else if (ClassType.isTypedDictClass(baseType)) {
if (ClassType.isTypedDictClass(baseType)) {
const typeFromTypedDict = getTypeOfIndexedTypedDict(
evaluatorInterface,
expression,
Expand All @@ -2778,6 +2772,39 @@ export function createTypeEvaluator(
return typeFromTypedDict.type;
}
}

let setItemType = getBoundMagicMethod(baseType, '__setitem__');
if (!setItemType) {
break;
}

if (isOverloaded(setItemType)) {
// Determine whether we need to use the slice overload.
const expectsSlice =
expression.d.items.length === 1 &&
expression.d.items[0].d.valueExpr.nodeType === ParseNodeType.Slice;
const overloads = OverloadedType.getOverloads(setItemType);
setItemType = overloads.find((overload) => {
if (overload.shared.parameters.length < 2) {
return false;
}

const keyType = FunctionType.getParamType(overload, 0);
const isSlice = isClassInstance(keyType) && ClassType.isBuiltIn(keyType, 'slice');
return expectsSlice === isSlice;
});

if (!setItemType) {
break;
}
}

if (isFunction(setItemType) && setItemType.shared.parameters.length >= 2) {
const paramType = FunctionType.getParamType(setItemType, 1);
if (!isAnyOrUnknown(paramType)) {
return paramType;
}
}
}
break;
}
Expand Down Expand Up @@ -19607,7 +19634,11 @@ export function createTypeEvaluator(
const isAsync = node.parent && node.parent.nodeType === ParseNodeType.With && !!node.parent.d.isAsync;

if (isOptionalType(exprType)) {
addDiagnostic(DiagnosticRule.reportOptionalContextManager, LocMessage.noneNotUsableWith(), node.d.expr);
addDiagnostic(
DiagnosticRule.reportOptionalContextManager,
isAsync ? LocMessage.noneNotUsableWithAsync() : LocMessage.noneNotUsableWith(),
node.d.expr
);
exprType = removeNoneFromUnion(exprType);
}

Expand All @@ -19620,25 +19651,20 @@ export function createTypeEvaluator(
return subtype;
}

const additionalHelp = new DiagnosticAddendum();
const enterDiag = new DiagnosticAddendum();

if (isClass(subtype)) {
let enterType = getTypeOfMagicMethodCall(
const enterTypeResult = getTypeOfMagicMethodCall(
subtype,
enterMethodName,
[],
node.d.expr,
/* inferenceContext */ undefined,
additionalHelp.createAddendum()
)?.type;

if (enterType) {
// For "async while", an implicit "await" is performed.
if (isAsync) {
enterType = getTypeOfAwaitable(enterType, node.d.expr);
}
enterDiag.createAddendum()
);

return enterType;
if (enterTypeResult) {
return isAsync ? getTypeOfAwaitable(enterTypeResult.type, node.d.expr) : enterTypeResult.type;
}

if (!isAsync) {
Expand All @@ -19651,22 +19677,24 @@ export function createTypeEvaluator(
/* inferenceContext */ undefined
)?.type
) {
additionalHelp.addMessage(LocAddendum.asyncHelp());
enterDiag.addMessage(LocAddendum.asyncHelp());
}
}
}

const message = isAsync ? LocMessage.typeNotUsableWithAsync() : LocMessage.typeNotUsableWith();
addDiagnostic(
DiagnosticRule.reportGeneralTypeIssues,
LocMessage.typeNotUsableWith().format({ type: printType(subtype), method: enterMethodName }) +
additionalHelp.getString(),
message.format({ type: printType(subtype), method: enterMethodName }) + enterDiag.getString(),
node.d.expr
);
return UnknownType.create();
});

// Verify that the target has an __exit__ or __aexit__ method defined.
const exitMethodName = isAsync ? '__aexit__' : '__exit__';
const exitDiag = new DiagnosticAddendum();

doForEachSubtype(exprType, (subtype) => {
subtype = makeTopLevelTypeVarsConcrete(subtype);

Expand All @@ -19676,24 +19704,27 @@ export function createTypeEvaluator(

if (isClass(subtype)) {
const anyArg: TypeResult = { type: AnyType.create() };
const exitType = getTypeOfMagicMethodCall(
const exitTypeResult = getTypeOfMagicMethodCall(
subtype,
exitMethodName,
[anyArg, anyArg, anyArg],
node.d.expr,
/* inferenceContext */ undefined
)?.type;
/* inferenceContext */ undefined,
exitDiag
);

if (exitType) {
return;
if (exitTypeResult) {
return isAsync ? getTypeOfAwaitable(exitTypeResult.type, node.d.expr) : exitTypeResult.type;
}
}

addDiagnostic(
DiagnosticRule.reportGeneralTypeIssues,
LocMessage.typeNotUsableWith().format({ type: printType(subtype), method: exitMethodName }),
LocMessage.typeNotUsableWith().format({ type: printType(subtype), method: exitMethodName }) +
exitDiag.getString(),
node.d.expr
);
return UnknownType.create();
});

if (node.d.target) {
Expand Down Expand Up @@ -20681,7 +20712,12 @@ export function createTypeEvaluator(
}

if (checkCodeFlowTooComplex(reference)) {
return FlowNodeTypeResult.create(/* type */ undefined, /* isIncomplete */ true);
return FlowNodeTypeResult.create(
/* type */ options?.typeAtStart && isUnbound(options.typeAtStart.type)
? UnknownType.create()
: undefined,
/* isIncomplete */ true
);
}

// Is there an code flow analyzer cached for this execution scope?
Expand Down Expand Up @@ -25705,18 +25741,6 @@ export function createTypeEvaluator(
flags: AssignTypeFlags,
recursionCount: number
) {
// Handle the special case where the dest type is a synthesized
// "self" for a protocol class.
if (
isTypeVar(destType) &&
destType.shared.isSynthesized &&
destType.shared.boundType &&
isClassInstance(destType.shared.boundType) &&
ClassType.isProtocolClass(destType.shared.boundType)
) {
return true;
}

if (isTypeVarTuple(destType) && !isUnpacked(srcType)) {
return false;
}
Expand Down
7 changes: 6 additions & 1 deletion packages/pyright-internal/src/analyzer/typeEvaluatorTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { Declaration } from './declaration';
import { ResolvedAliasInfo } from './declarationUtils';
import { SymbolWithScope } from './scope';
import { Symbol, SynthesizedTypeInfo } from './symbol';
import { SpeculativeModeOptions } from './typeCacheUtils';
import { PrintTypeFlags } from './typePrinter';
import {
AnyType,
Expand Down Expand Up @@ -843,7 +844,11 @@ export interface TypeEvaluator {

getTypeCacheEntryCount: () => number;
disposeEvaluator: () => void;
useSpeculativeMode: <T>(speculativeNode: ParseNode | undefined, callback: () => T) => T;
useSpeculativeMode: <T>(
speculativeNode: ParseNode | undefined,
callback: () => T,
options?: SpeculativeModeOptions
) => T;
isSpeculativeModeInUse: (node: ParseNode | undefined) => boolean;
setTypeResultForNode: (node: ParseNode, typeResult: TypeResult, flags?: EvalFlags) => void;

Expand Down
26 changes: 16 additions & 10 deletions packages/pyright-internal/src/analyzer/typeGuards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1249,20 +1249,15 @@ function narrowTypeForInstanceOrSubclassInternal(
if (!isInstanceCheck) {
const isTypeInstance = isClassInstance(subtype) && ClassType.isBuiltIn(subtype, 'type');

// Handle metaclass instances specially.
if (isMetaclassInstance(subtype) && !isTypeInstance) {
// Handle metaclass instances specially.
adjFilterTypes = filterTypes.map((filterType) => convertToInstantiable(filterType));
} else {
const convSubtype = convertToInstance(subtype);
adjSubtype = convertToInstance(subtype);

// Handle type[Any] specially for this case.
if (isClassInstance(subtype) && ClassType.isBuiltIn(subtype, 'type') && isAnyOrUnknown(convSubtype)) {
adjSubtype = convertToInstance(evaluator.getObjectType());
} else {
adjSubtype = convSubtype;
if (!isAnyOrUnknown(subtype) || isPositiveTest) {
resultRequiresAdj = true;
}

resultRequiresAdj = true;
}
}

Expand All @@ -1276,7 +1271,18 @@ function narrowTypeForInstanceOrSubclassInternal(
errorNode
);

return resultRequiresAdj ? convertToInstantiable(narrowedResult) : narrowedResult;
if (!resultRequiresAdj) {
return narrowedResult;
}

if (isAnyOrUnknown(narrowedResult)) {
const typeClass = evaluator.getTypeClassType();
if (typeClass) {
return ClassType.specialize(ClassType.cloneAsInstance(typeClass), [narrowedResult]);
}
}

return convertToInstantiable(narrowedResult);
});

return result;
Expand Down
2 changes: 1 addition & 1 deletion packages/pyright-internal/src/common/fullAccessHost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ export class FullAccessHost extends LimitedAccessHost {
}

/**
* Excecutes a chunk of Python code via the provided interpreter and returns the output.
* Executes a chunk of Python code via the provided interpreter and returns the output.
* @param interpreterPath Path to interpreter.
* @param commandLineArgs Command line args for interpreter other than the code to execute.
* @param code Code to execute.
Expand Down
Loading

0 comments on commit b81f655

Please sign in to comment.