Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge 1.1.385 #782

Merged
merged 15 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.384",
"version": "1.1.385",
"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.384",
"version": "1.1.385",
"license": "MIT",
"private": true,
"files": [
Expand Down
6 changes: 4 additions & 2 deletions packages/pyright-internal/src/analyzer/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ import {
UnresolvedModuleMarker,
VariableDeclaration,
} from './declaration';
import { extractParameterDocumentation } from './docStringUtils';
import { ImplicitImport, ImportResult, ImportType } from './importResult';
import * as ParseTreeUtils from './parseTreeUtils';
import { ParseTreeWalker } from './parseTreeWalker';
Expand Down Expand Up @@ -563,7 +562,10 @@ export class Binder extends ParseTreeWalker {
// Extract the parameter docString from the function docString
let docString = ParseTreeUtils.getDocString(node?.d.suite?.d.statements ?? []);
if (docString !== undefined) {
docString = extractParameterDocumentation(docString, paramNode.d.name.d.value);
docString = this._docStringService.extractParameterDocumentation(
docString,
paramNode.d.name.d.value
);
}

if (symbol) {
Expand Down
5 changes: 0 additions & 5 deletions packages/pyright-internal/src/analyzer/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1288,11 +1288,6 @@ export class Checker extends ParseTreeWalker {
}

override visitBinaryOperation(node: BinaryOperationNode): boolean {
if (node.d.operator === OperatorType.And || node.d.operator === OperatorType.Or) {
this._validateConditionalIsBool(node.d.leftExpr);
this._validateConditionalIsBool(node.d.rightExpr);
}

if (node.d.operator === OperatorType.Equals || node.d.operator === OperatorType.NotEquals) {
// Don't apply this rule if it's within an assert.
if (!ParseTreeUtils.isWithinAssertExpression(node)) {
Expand Down
18 changes: 10 additions & 8 deletions packages/pyright-internal/src/analyzer/constructors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -595,15 +595,17 @@ function validateMetaclassCall(
);
});

// If the return type is unannotated, don't use the inferred return type.
const callType = metaclassCallMethodInfo.type;
if (isFunction(callType) && !callType.shared.declaredReturnType) {
return undefined;
}
if (!callResult.argumentErrors) {
// If the return type is unannotated, don't use the inferred return type.
const callType = metaclassCallMethodInfo.type;
if (isFunction(callType) && !callType.shared.declaredReturnType) {
return undefined;
}

// If the return type is unknown, ignore it.
if (callResult.returnType && isUnknown(callResult.returnType)) {
return undefined;
// If the return type is unknown, ignore it.
if (callResult.returnType && isUnknown(callResult.returnType)) {
return undefined;
}
}

return callResult;
Expand Down
39 changes: 37 additions & 2 deletions packages/pyright-internal/src/analyzer/dataClasses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,21 @@ import {
ParseNodeType,
TypeAnnotationNode,
} from '../parser/parseNodes';
import { Tokenizer } from '../parser/tokenizer';
import * as AnalyzerNodeInfo from './analyzerNodeInfo';
import { getFileInfo } from './analyzerNodeInfo';
import { ConstraintSolution } from './constraintSolution';
import { ConstraintTracker } from './constraintTracker';
import { createFunctionFromConstructor, getBoundInitMethod } from './constructors';
import { DeclarationType, VariableDeclaration } from './declaration';
import { updateNamedTupleBaseClass } from './namedTuples';
import { getClassFullName, getEnclosingClassOrFunction, getScopeIdForNode, getTypeSourceId } from './parseTreeUtils';
import {
getClassFullName,
getEnclosingClassOrFunction,
getScopeIdForNode,
getTypeSourceId,
getTypeVarScopesForNode,
} from './parseTreeUtils';
import { evaluateStaticBoolExpression } from './staticExpressions';
import { Symbol, SymbolFlags } from './symbol';
import { isPrivateName } from './symbolNameUtils';
Expand Down Expand Up @@ -73,6 +80,9 @@ import {
getTypeVarScopeIds,
isLiteralType,
isMetaclassInstance,
makeInferenceContext,
makeTypeVarsBound,
makeTypeVarsFree,
requiresSpecialization,
specializeTupleClass,
synthesizeTypeVarForSelfCls,
Expand Down Expand Up @@ -325,6 +335,14 @@ export function synthesizeDataClassMethods(
isLiteralType(valueType)
) {
aliasName = valueType.priv.literalValue as string;

if (!Tokenizer.isPythonIdentifier(aliasName)) {
evaluator.addDiagnostic(
DiagnosticRule.reportGeneralTypeIssues,
LocMessage.dataClassFieldInvalidAlias().format({ aliasName }),
aliasArg.d.valueExpr
);
}
}
}

Expand Down Expand Up @@ -571,7 +589,24 @@ export function synthesizeDataClassMethods(
if (entry.isDefaultFactory || !entry.defaultExpr) {
defaultType = entry.type;
} else {
defaultType = evaluator.getTypeOfExpression(entry.defaultExpr).type;
const defaultExpr = entry.defaultExpr;
const fileInfo = AnalyzerNodeInfo.getFileInfo(node);
const flags = fileInfo.isStubFile ? EvalFlags.ConvertEllipsisToAny : EvalFlags.None;
const liveTypeVars = getTypeVarScopesForNode(entry.defaultExpr);
const boundEffectiveType = makeTypeVarsBound(effectiveType, liveTypeVars);

// Use speculative mode here so we don't cache the results.
// We'll want to re-evaluate this expression later, potentially
// with different evaluation flags.
defaultType = evaluator.useSpeculativeMode(defaultExpr, () => {
return evaluator.getTypeOfExpression(
defaultExpr,
flags,
makeInferenceContext(boundEffectiveType)
).type;
});

defaultType = makeTypeVarsFree(defaultType, liveTypeVars);
}
}
}
Expand Down
14 changes: 2 additions & 12 deletions packages/pyright-internal/src/analyzer/importResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import * as StringUtils from '../common/stringUtils';
import { equateStringsCaseInsensitive } from '../common/stringUtils';
import { Uri } from '../common/uri/uri';
import { getFileSystemEntriesFromDirEntries, isDirectory, isFile, tryRealpath, tryStat } from '../common/uri/uriUtils';
import { isIdentifierChar, isIdentifierStartChar } from '../parser/characters';
import { Tokenizer } from '../parser/tokenizer';
import { ImplicitImport, ImportResult, ImportType } from './importResult';
import { getDirectoryLeadingDotsPointsTo } from './importStatementUtils';
import { ImportPath, ParentDirectoryCache } from './parentDirectoryCache';
Expand Down Expand Up @@ -2834,7 +2834,7 @@ function _getModuleNameInfoFromPath(
}

// Check whether parts contains invalid characters.
const containsInvalidCharacters = parts.some((p) => !_isIdentifier(p));
const containsInvalidCharacters = parts.some((p) => !Tokenizer.isPythonIdentifier(p));

return {
moduleName: parts.join('.'),
Expand All @@ -2849,13 +2849,3 @@ function _isNativeModuleFileExtension(fileExtension: string): boolean {
function _isDefaultWorkspace(uri: Uri | undefined) {
return !uri || uri.isEmpty() || Uri.isDefaultWorkspace(uri);
}

function _isIdentifier(value: string) {
for (let i = 0; i < value.length; i++) {
if (i === 0 ? !isIdentifierStartChar(value.charCodeAt(i)) : !isIdentifierChar(value.charCodeAt(i))) {
return false;
}
}

return true;
}
3 changes: 2 additions & 1 deletion packages/pyright-internal/src/analyzer/parameterUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export enum ParamKind {
Positional,
Standard,
Keyword,
ExpandedArgs,
}

export interface VirtualParamDetails {
Expand Down Expand Up @@ -185,7 +186,7 @@ export function getParamListDetails(type: FunctionType): ParamListDetails {
index,
tupleArg.type,
/* defaultArgTypeOverride */ undefined,
ParamKind.Positional
ParamKind.ExpandedArgs
);

if (category === ParamCategory.Simple) {
Expand Down
82 changes: 51 additions & 31 deletions packages/pyright-internal/src/analyzer/typeEvaluator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3552,11 +3552,6 @@ export function createTypeEvaluator(
}
}

if (declaredType) {
const liveScopeIds = ParseTreeUtils.getTypeVarScopesForNode(nameNode);
declaredType = makeTypeVarsBound(declaredType, liveScopeIds);
}

// We found an existing declared type. Make sure the type is assignable.
let destType = typeResult.type;
const isTypeAlias =
Expand All @@ -3565,7 +3560,11 @@ export function createTypeEvaluator(
if (declaredType && !isTypeAlias) {
let diagAddendum = new DiagnosticAddendum();

if (!assignType(declaredType, typeResult.type, diagAddendum)) {
const liveScopeIds = ParseTreeUtils.getTypeVarScopesForNode(nameNode);
const boundDeclaredType = makeTypeVarsBound(declaredType, liveScopeIds);
const srcType = makeTypeVarsBound(typeResult.type, liveScopeIds);

if (!assignType(boundDeclaredType, srcType, diagAddendum)) {
// If there was an expected type mismatch, use that diagnostic
// addendum because it will be more informative.
if (expectedTypeDiagAddendum) {
Expand Down Expand Up @@ -3892,7 +3891,7 @@ export function createTypeEvaluator(
const tupleType = getSpecializedTupleType(subtype);
if (tupleType && tupleType.priv.tupleTypeArgs) {
const sourceEntryTypes = tupleType.priv.tupleTypeArgs.map((t) =>
addConditionToType(t.type, getTypeCondition(subtype), /* skipSelfCondition */ true)
addConditionToType(t.type, getTypeCondition(subtype), { skipSelfCondition: true })
);

const unboundedIndex = tupleType.priv.tupleTypeArgs.findIndex((t) => t.isUnbounded);
Expand Down Expand Up @@ -5716,11 +5715,10 @@ export function createTypeEvaluator(

if (typeResult) {
if (!typeResult.typeErrors) {
type = addConditionToType(
typeResult.type,
getTypeCondition(baseType),
/* skipSelfCondition */ true
);
type = addConditionToType(typeResult.type, getTypeCondition(baseType), {
skipSelfCondition: true,
skipBoundTypeVars: true,
});
} else {
typeErrors = true;
}
Expand All @@ -5737,7 +5735,7 @@ export function createTypeEvaluator(
narrowedTypeForSet = addConditionToType(
typeResult.narrowedTypeForSet,
getTypeCondition(baseType),
/* skipSelfCondition */ true
{ skipSelfCondition: true, skipBoundTypeVars: true }
);
}

Expand Down Expand Up @@ -5869,7 +5867,9 @@ export function createTypeEvaluator(
const typeResult = getTypeOfBoundMember(node.d.member, subtype, memberName, usage, diag);

if (typeResult && !typeResult.typeErrors) {
type = addConditionToType(typeResult.type, getTypeCondition(baseType));
type = addConditionToType(typeResult.type, getTypeCondition(baseType), {
skipBoundTypeVars: true,
});
if (typeResult.isIncomplete) {
isIncomplete = true;
}
Expand Down Expand Up @@ -12104,7 +12104,7 @@ export function createTypeEvaluator(
eliminateUnsolvedInUnions,
},
});
specializedReturnType = addConditionToType(specializedReturnType, typeCondition);
specializedReturnType = addConditionToType(specializedReturnType, typeCondition, { skipBoundTypeVars: true });

// If the function includes a ParamSpec and the captured signature(s) includes
// generic types, we may need to apply those solved TypeVars.
Expand Down Expand Up @@ -15456,17 +15456,32 @@ export function createTypeEvaluator(
// As per the specification, we support None, int, bool, str, bytes literals
// plus enum values.
const literalTypes: Type[] = [];
let isValidTypeForm = true;

for (const item of node.d.items) {
let type: Type | undefined;
const itemExpr = item.d.valueExpr;

if (item.d.argCategory !== ArgCategory.Simple) {
addDiagnostic(DiagnosticRule.reportInvalidTypeForm, LocMessage.unpackedArgInTypeArgument(), itemExpr);
type = UnknownType.create();
if ((flags & EvalFlags.TypeExpression) !== 0) {
addDiagnostic(
DiagnosticRule.reportInvalidTypeForm,
LocMessage.unpackedArgInTypeArgument(),
itemExpr
);
type = UnknownType.create();
isValidTypeForm = false;
}
} else if (item.d.name) {
addDiagnostic(DiagnosticRule.reportInvalidTypeForm, LocMessage.keywordArgInTypeArgument(), itemExpr);
type = UnknownType.create();
if ((flags & EvalFlags.TypeExpression) !== 0) {
addDiagnostic(
DiagnosticRule.reportInvalidTypeForm,
LocMessage.keywordArgInTypeArgument(),
itemExpr
);
type = UnknownType.create();
isValidTypeForm = false;
}
} else if (itemExpr.nodeType === ParseNodeType.StringList) {
const isBytes = (itemExpr.d.strings[0].d.token.flags & StringTokenFlags.Bytes) !== 0;
const value = itemExpr.d.strings.map((s) => s.d.value).join('');
Expand All @@ -15476,15 +15491,18 @@ export function createTypeEvaluator(
type = cloneBuiltinClassWithLiteral(node, classType, 'str', value);
}

itemExpr.d.strings.forEach((stringNode) => {
if ((stringNode.d.token.flags & StringTokenFlags.NamedUnicodeEscape) !== 0) {
addDiagnostic(
DiagnosticRule.reportInvalidTypeForm,
LocMessage.literalNamedUnicodeEscape(),
stringNode
);
}
});
if ((flags & EvalFlags.TypeExpression) !== 0) {
itemExpr.d.strings.forEach((stringNode) => {
if ((stringNode.d.token.flags & StringTokenFlags.NamedUnicodeEscape) !== 0) {
addDiagnostic(
DiagnosticRule.reportInvalidTypeForm,
LocMessage.literalNamedUnicodeEscape(),
stringNode
);
isValidTypeForm = false;
}
});
}
} else if (itemExpr.nodeType === ParseNodeType.Number) {
if (!itemExpr.d.isImaginary && itemExpr.d.isInteger) {
type = cloneBuiltinClassWithLiteral(node, classType, 'int', itemExpr.d.value);
Expand Down Expand Up @@ -15549,6 +15567,7 @@ export function createTypeEvaluator(
if ((flags & EvalFlags.TypeExpression) !== 0) {
addDiagnostic(DiagnosticRule.reportInvalidTypeForm, LocMessage.literalUnsupportedType(), item);
type = UnknownType.create();
isValidTypeForm = false;
} else {
return ClassType.cloneAsInstance(classType);
}
Expand All @@ -15563,7 +15582,7 @@ export function createTypeEvaluator(
result = TypeBase.cloneAsSpecialForm(result, ClassType.cloneAsInstance(unionTypeClass));
}

if (isTypeFormSupported(node)) {
if (isTypeFormSupported(node) && isValidTypeForm) {
result = TypeBase.cloneWithTypeForm(result, convertToInstance(result));
}

Expand Down Expand Up @@ -25860,13 +25879,14 @@ export function createTypeEvaluator(
const destParamName = destParam.param.name ?? '';
const srcParamName = srcParam.param.name ?? '';
if (destParamName) {
const isDestPositionalOnly = destParam.kind === ParamKind.Positional;
const isDestPositionalOnly =
destParam.kind === ParamKind.Positional || destParam.kind === ParamKind.ExpandedArgs;
if (
!isDestPositionalOnly &&
destParam.param.category !== ParamCategory.ArgsList &&
srcParam.param.category !== ParamCategory.ArgsList
) {
if (srcParam.kind === ParamKind.Positional) {
if (srcParam.kind === ParamKind.Positional || srcParam.kind === ParamKind.ExpandedArgs) {
diag?.createAddendum().addMessage(
LocAddendum.functionParamPositionOnly().format({
name: destParamName,
Expand Down
Loading
Loading