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

Push pylance changes to pyright #6389

Merged
merged 1 commit into from
Nov 8, 2023
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 packages/pyright-internal/src/analyzer/importResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ interface SupportedVersionRange {

const supportedNativeLibExtensions = ['.pyd', '.so', '.dylib'];
const supportedSourceFileExtensions = ['.py', '.pyi'];
const supportedFileExtensions = [...supportedSourceFileExtensions, ...supportedNativeLibExtensions];
export const supportedFileExtensions = [...supportedSourceFileExtensions, ...supportedNativeLibExtensions];

// Should we allow partial resolution for third-party packages? Some use tricks
// to populate their package namespaces, so we might be able to partially resolve
Expand Down
48 changes: 44 additions & 4 deletions packages/pyright-internal/src/analyzer/importStatementUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import * as AnalyzerNodeInfo from './analyzerNodeInfo';
import { ModuleNameAndType } from './importResolver';
import { ImportResult, ImportType } from './importResult';
import * as SymbolNameUtils from './symbolNameUtils';
import { findTokenAfter, getTokenAt } from './parseTreeUtils';
import { TokenType } from '../parser/tokenizerTypes';

export interface ImportStatement {
node: ImportNode | ImportFromNode;
Expand Down Expand Up @@ -749,6 +751,7 @@ export function getImportGroupFromModuleNameAndType(moduleNameAndType: ModuleNam
}

export function getTextRangeForImportNameDeletion(
parseResults: ParseResults,
nameNodes: ImportAsNode[] | ImportFromAsNode[],
...nameNodeIndexToDelete: number[]
): TextRange[] {
Expand All @@ -757,14 +760,15 @@ export function getTextRangeForImportNameDeletion(
const startNode = nameNodes[pair.start];
const endNode = nameNodes[pair.end];

if (pair.start === 0 && nameNodes.length === pair.end - pair.start + 1) {
if (pair.start === 0 && nameNodes.length === pair.end + 1) {
// get span of whole statement. ex) "import [|A|]" or "import [|A, B|]"
editSpans.push(TextRange.fromBounds(startNode.start, TextRange.getEnd(endNode)));
} else if (pair.end === nameNodes.length - 1) {
// get span of "import A[|, B|]" or "import A[|, B, C|]"
const start = TextRange.getEnd(nameNodes[pair.start - 1]);
const length = TextRange.getEnd(endNode) - start;
editSpans.push({ start, length });
const previousNode = nameNodes[pair.start - 1];
editSpans.push(
...getEditsPreservingFirstCommentAfterCommaIfExist(parseResults, previousNode, startNode, endNode)
);
} else {
// get span of "import [|A, |]B" or "import [|A, B,|] C"
const start = startNode.start;
Expand All @@ -775,6 +779,42 @@ export function getTextRangeForImportNameDeletion(
return editSpans;
}

function getEditsPreservingFirstCommentAfterCommaIfExist(
parseResults: ParseResults,
previousNode: ParseNode,
startNode: ParseNode,
endNode: ParseNode
): TextRange[] {
const offsetOfPreviousNodeEnd = TextRange.getEnd(previousNode);
const startingToken = getTokenAt(parseResults.tokenizerOutput.tokens, startNode.start);
if (!startingToken || !startingToken.comments || startingToken.comments.length === 0) {
const length = TextRange.getEnd(endNode) - offsetOfPreviousNodeEnd;
return [{ start: offsetOfPreviousNodeEnd, length }];
}

const commaToken = findTokenAfter(parseResults, TextRange.getEnd(previousNode), (t) => t.type === TokenType.Comma);
if (!commaToken) {
const length = TextRange.getEnd(endNode) - offsetOfPreviousNodeEnd;
return [{ start: offsetOfPreviousNodeEnd, length }];
}

// We have code something like
// previousNode, #comment
// startNode,
// endNode
//
// Make sure we preserve #comment when deleting start/end nodes so we have
// previousNode #comment
// as final result.
const lengthToComma = TextRange.getEnd(commaToken) - offsetOfPreviousNodeEnd;
const offsetToCommentEnd = TextRange.getEnd(startingToken.comments[startingToken.comments.length - 1]);
const length = TextRange.getEnd(endNode) - offsetToCommentEnd;
return [
{ start: offsetOfPreviousNodeEnd, length: lengthToComma },
{ start: offsetToCommentEnd, length },
];
}

function getConsecutiveNumberPairs(indices: number[]) {
if (indices.length === 0) {
return [];
Expand Down
18 changes: 18 additions & 0 deletions packages/pyright-internal/src/analyzer/parseTreeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1808,6 +1808,24 @@ export function getTokenOverlapping(tokens: TextRangeCollection<Token>, position
return TextRange.overlaps(token, position) ? token : undefined;
}

export function findTokenAfter(parseResults: ParseResults, offset: number, predicate: (t: Token) => boolean) {
const tokens = parseResults.tokenizerOutput.tokens;

const index = tokens.getItemAtPosition(offset);
if (index < 0) {
return undefined;
}

for (let i = index; i < tokens.length; i++) {
const token = tokens.getItemAt(i);
if (predicate(token)) {
return token;
}
}

return undefined;
}

export function printParseNodeType(type: ParseNodeType) {
switch (type) {
case ParseNodeType.Error:
Expand Down
11 changes: 8 additions & 3 deletions packages/pyright-internal/src/analyzer/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ export class Program {
this._logTracker = logTracker ?? new LogTracker(this._console, 'FG');
this._importResolver = initialImportResolver;
this._configOptions = initialConfigOptions;

this._sourceFileFactory = serviceProvider.sourceFileFactory();

this._cacheManager = serviceProvider.tryGet(ServiceKeys.cacheManager) ?? new CacheManager();
Expand Down Expand Up @@ -430,7 +431,7 @@ export class Program {
sourceFileInfo.diagnosticsVersion = 0;
}

verifyNoCyclesInChainedFiles(sourceFileInfo);
verifyNoCyclesInChainedFiles(this, sourceFileInfo);
sourceFileInfo.sourceFile.setClientVersion(version, contents);
}

Expand All @@ -449,7 +450,7 @@ export class Program {
sourceFileInfo.sourceFile.markDirty();
this._markFileDirtyRecursive(sourceFileInfo, new Set<string>());

verifyNoCyclesInChainedFiles(sourceFileInfo);
verifyNoCyclesInChainedFiles(this, sourceFileInfo);
}

setFileClosed(filePath: string, isTracked?: boolean): FileDiagnostics[] {
Expand Down Expand Up @@ -1675,7 +1676,11 @@ export class Program {
const implicitPath = nextImplicitImport.sourceFile.getFilePath();
if (implicitSet.has(implicitPath)) {
// We've found a cycle. Break out of the loop.
debug.fail(`Found a cycle in implicit imports files`);
debug.fail(
this.serviceProvider
.tryGet(ServiceKeys.debugInfoInspector)
?.getCycleDetail(this, nextImplicitImport) ?? `Found a cycle in implicit imports files`
);
}

implicitSet.add(implicitPath);
Expand Down
18 changes: 14 additions & 4 deletions packages/pyright-internal/src/analyzer/sourceFileInfoUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
* Functions that operate on SourceFileInfo objects.
*/

import { assert, fail } from '../common/debug';
import { fail } from '../common/debug';
import { ProgramView, SourceFileInfo } from '../common/extensibility';
import { ServiceKeys } from '../common/serviceProviderExtensions';
import { IPythonMode } from './sourceFile';

export function isUserCode(fileInfo: SourceFileInfo | undefined) {
Expand All @@ -27,7 +28,7 @@ export function collectImportedByCells<T extends SourceFileInfo>(program: Progra
return importedByCells;
}

export function verifyNoCyclesInChainedFiles<T extends SourceFileInfo>(fileInfo: T): void {
export function verifyNoCyclesInChainedFiles<T extends SourceFileInfo>(program: ProgramView, fileInfo: T): void {
let nextChainedFile = fileInfo.chainedSourceFile;
if (!nextChainedFile) {
return;
Expand All @@ -38,7 +39,11 @@ export function verifyNoCyclesInChainedFiles<T extends SourceFileInfo>(fileInfo:
const path = nextChainedFile.sourceFile.getFilePath();
if (set.has(path)) {
// We found a cycle.
fail(`Found a cycle in implicit imports files`);
fail(
program.serviceProvider
.tryGet(ServiceKeys.debugInfoInspector)
?.getCycleDetail(program, nextChainedFile) ?? `Found a cycle in implicit imports files`
);
}

set.add(path);
Expand All @@ -62,7 +67,12 @@ export function createChainedByList<T extends SourceFileInfo>(program: ProgramVi
const chainedByList: SourceFileInfo[] = [fileInfo];
let current: SourceFileInfo | undefined = fileInfo;
while (current) {
assert(!visited.has(current), 'detected a cycle in chained files');
if (visited.has(current)) {
fail(
program.serviceProvider.tryGet(ServiceKeys.debugInfoInspector)?.getCycleDetail(program, current) ??
'detected a cycle in chained files'
);
}
visited.add(current);

current = map.get(current);
Expand Down
4 changes: 4 additions & 0 deletions packages/pyright-internal/src/common/extensibility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,7 @@ export interface StatusMutationListener {
clearCache?: () => void;
updateSettings?: <T extends ServerSettings>(settings: T) => void;
}

export interface DebugInfoInspector {
getCycleDetail(program: ProgramView, fileInfo: SourceFileInfo): string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
ServiceProvider as ReadOnlyServiceProvider,
SymbolDefinitionProvider,
SymbolUsageProviderFactory,
DebugInfoInspector,
} from './extensibility';
import { FileSystem, TempFile } from './fileSystem';
import { LogTracker } from './logTracker';
Expand All @@ -39,6 +40,7 @@ export namespace ServiceKeys {
export const stateMutationListeners = new GroupServiceKey<StatusMutationListener>();
export const tempFile = new ServiceKey<TempFile>();
export const cacheManager = new ServiceKey<CacheManager>();
export const debugInfoInspector = new ServiceKey<DebugInfoInspector>();
}

export function createServiceProvider(...services: any): ServiceProvider {
Expand Down
3 changes: 2 additions & 1 deletion packages/pyright-internal/src/common/textEditTracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export class TextEditTracker {

const filePath = getFileInfo(parseResults.parseTree).filePath;
const ranges = getTextRangeForImportNameDeletion(
parseResults,
imports,
imports.findIndex((v) => v === importToDelete)
);
Expand Down Expand Up @@ -395,7 +396,7 @@ export class TextEditTracker {
return false;
}

const editSpans = getTextRangeForImportNameDeletion(nameNodes, ...indices);
const editSpans = getTextRangeForImportNameDeletion(nodeToRemove.parseResults, nameNodes, ...indices);
editSpans.forEach((e) => this.addEdit(info.filePath, convertTextRangeToRange(e, info.lines), ''));

this._removeNodesHandled(nodesRemoved);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@
"superCallFirstArg": "Jako první argument pro volání super se očekával typ třídy, ale přijal se {type}",
"superCallSecondArg": "Druhý argument volání super musí být objekt nebo třída odvozená z typu {type}",
"superCallZeroArgForm": "Forma nulového argumentu „super“ volání je platná pouze v rámci metody.",
"superCallZeroArgFormStaticMethod": "Zero-argument form of \"super\" call is not valid within a static method",
"symbolIsPossiblyUnbound": "{name} je pravděpodobně nevázané",
"symbolIsUnbound": "Název {name} je nevázaný",
"symbolIsUndefined": "{name} není definované",
Expand Down Expand Up @@ -609,6 +610,8 @@
"conditionalRequiresBool": "Metoda __bool__ pro typ {operandType} vrací typ {boolReturnType} místo bool",
"dataClassFieldLocation": "Deklarace pole",
"dataClassFrozen": "{name} je zablokované",
"descriptorAccessBindingFailed": "Failed to bind method \"{name}\" for descriptor class \"{className}\"",
"descriptorAccessCallFailed": "Failed to call method \"{name}\" for descriptor class \"{className}\"",
"finalMethod": "Konečná metoda",
"functionParamDefaultMissing": "V parametru „{name}“ chybí výchozí argument",
"functionParamName": "Neshoda názvu parametru: {destName} a {srcName}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@
"superCallFirstArg": "Klassentyp als erstes Argument für super-Aufruf erwartet, aber \"{type}\" empfangen",
"superCallSecondArg": "Das zweite Argument für den \"super\"-Aufruf muss ein Objekt oder eine Klasse sein, das bzw. die von \"{type}\" abgeleitet wird.",
"superCallZeroArgForm": "Die Nullargumentform des „Superaufrufs“ ist nur innerhalb einer Methode gültig.",
"superCallZeroArgFormStaticMethod": "Zero-argument form of \"super\" call is not valid within a static method",
"symbolIsPossiblyUnbound": "\"{name}\" ist möglicherweise ungebunden.",
"symbolIsUnbound": "\"{name}\" ist ungebunden.",
"symbolIsUndefined": "\"{name}\" ist nicht definiert.",
Expand Down Expand Up @@ -609,6 +610,8 @@
"conditionalRequiresBool": "Die Methode __bool__ für den Typ \"{operandType}\" gibt den Typ \"{boolReturnType}\" anstelle von \"bool\" zurück",
"dataClassFieldLocation": "Felddeklaration",
"dataClassFrozen": "\"{name}\" ist fixiert",
"descriptorAccessBindingFailed": "Failed to bind method \"{name}\" for descriptor class \"{className}\"",
"descriptorAccessCallFailed": "Failed to call method \"{name}\" for descriptor class \"{className}\"",
"finalMethod": "Endgültige Methode",
"functionParamDefaultMissing": "Standardargument für Parameter \"{name}\" fehlt.",
"functionParamName": "Parameternamen stimmen nicht überein: \"{destName}\" und \"{srcName}\"",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@
"superCallFirstArg": "Se esperaba el tipo de clase como primer argumento de la llamada a \"super\" pero se recibió \"{type}\"",
"superCallSecondArg": "El segundo argumento de la llamada a \"super\" debe ser un objeto o clase que derive de \"{type}\"",
"superCallZeroArgForm": "La forma sin argumentos de la llamada \"super\" sólo es válida dentro de un método",
"superCallZeroArgFormStaticMethod": "Zero-argument form of \"super\" call is not valid within a static method",
"symbolIsPossiblyUnbound": "\"{name}\" está posiblemente desvinculado",
"symbolIsUnbound": "\"{name}\" está sin consolidar",
"symbolIsUndefined": "\"{name}\" no está definido",
Expand Down Expand Up @@ -609,6 +610,8 @@
"conditionalRequiresBool": "El método __bool__ para el tipo \"{operandType}\" devuelve el tipo \"{boolReturnType}\" en lugar de \"bool\"",
"dataClassFieldLocation": "en declaración de campo",
"dataClassFrozen": "\"{name}\" está congelado",
"descriptorAccessBindingFailed": "Failed to bind method \"{name}\" for descriptor class \"{className}\"",
"descriptorAccessCallFailed": "Failed to call method \"{name}\" for descriptor class \"{className}\"",
bschnurr marked this conversation as resolved.
Show resolved Hide resolved
"finalMethod": "Método final",
"functionParamDefaultMissing": "Falta el argumento predeterminado en el parámetro \"{name}\"",
"functionParamName": "Nombre de parámetro no coincidente: \"{destName}\" frente a \"{srcName}\"",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@
"superCallFirstArg": "Type de classe attendu en tant que premier argument de l’appel « super », mais « {type} » reçu",
"superCallSecondArg": "Le deuxième argument de l’appel « super » doit être un objet ou une classe dérivé de « {type} »",
"superCallZeroArgForm": "La forme sans argument d'appel \"super\" n'est valide que dans une méthode",
"superCallZeroArgFormStaticMethod": "Zero-argument form of \"super\" call is not valid within a static method",
"symbolIsPossiblyUnbound": "« {name} » est peut-être indépendant",
"symbolIsUnbound": "« {name} » est indépendant",
"symbolIsUndefined": "« {name} » n’est pas défini",
Expand Down Expand Up @@ -609,6 +610,8 @@
"conditionalRequiresBool": "La méthode __bool__ pour le type « {operandType} » retourne le type « {boolReturnType} » plutôt que « bool »",
"dataClassFieldLocation": "Déclaration de champ",
"dataClassFrozen": "« {name} » est figé",
"descriptorAccessBindingFailed": "Failed to bind method \"{name}\" for descriptor class \"{className}\"",
"descriptorAccessCallFailed": "Failed to call method \"{name}\" for descriptor class \"{className}\"",
"finalMethod": "Méthode finale",
"functionParamDefaultMissing": "Le paramètre \"{name}\" n'a pas d'argument par défaut",
"functionParamName": "Incompatibilité de nom de paramètre : « {destName} » et « {srcName} »",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@
"superCallFirstArg": "È previsto un tipo di classe come primo argomento della chiamata \"super\", ma è stato ricevuto \"{type}\"",
"superCallSecondArg": "Il secondo argomento della chiamata \"super\" deve essere un oggetto o una classe che deriva da \"{type}\"",
"superCallZeroArgForm": "Il modulo zero-argument della chiamata \"super\" è valido solo all'interno di un metodo",
"superCallZeroArgFormStaticMethod": "Zero-argument form of \"super\" call is not valid within a static method",
"symbolIsPossiblyUnbound": "\"{name}\" potrebbe non essere associato",
"symbolIsUnbound": "\"{name}\" non associato",
"symbolIsUndefined": "\"{name}\" non è definito",
Expand Down Expand Up @@ -609,6 +610,8 @@
"conditionalRequiresBool": "Il metodo __bool__ per il tipo \"{operandType}\" restituisce il tipo \"{boolReturnType}\" anziché \"bool\"",
"dataClassFieldLocation": "Dichiarazione di campo",
"dataClassFrozen": "\"{name}\" è bloccato",
"descriptorAccessBindingFailed": "Failed to bind method \"{name}\" for descriptor class \"{className}\"",
"descriptorAccessCallFailed": "Failed to call method \"{name}\" for descriptor class \"{className}\"",
"finalMethod": "Metodo finale",
"functionParamDefaultMissing": "Nel parametro \"{name}\" manca un argomento predefinito",
"functionParamName": "Nome del parametro non corrispondente: \"{destName}\" rispetto a \"{srcName}\"",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@
"superCallFirstArg": "\"super\" 呼び出しの最初の引数としてクラス型が必要ですが、\"{type}\" を受け取りました",
"superCallSecondArg": "\"super\" 呼び出しの 2 番目の引数は、\"{type}\" から派生したオブジェクトまたはクラスである必要があります",
"superCallZeroArgForm": "\"super\" 呼び出しの 0 引数形式は、メソッド内でのみ有効です",
"superCallZeroArgFormStaticMethod": "Zero-argument form of \"super\" call is not valid within a static method",
"symbolIsPossiblyUnbound": "\"{name}\" はバインドされていない可能性があります",
"symbolIsUnbound": "\"{name}\" はバインドされていません",
"symbolIsUndefined": "\"{name}\" が定義されていません",
Expand Down Expand Up @@ -609,6 +610,8 @@
"conditionalRequiresBool": "型 \"{operandType}\" のメソッド __bool__は、\"bool\" ではなく型 \"{boolReturnType}\" を返します",
"dataClassFieldLocation": "フィールド宣言",
"dataClassFrozen": "\"{name}\" は固定されています",
"descriptorAccessBindingFailed": "Failed to bind method \"{name}\" for descriptor class \"{className}\"",
"descriptorAccessCallFailed": "Failed to call method \"{name}\" for descriptor class \"{className}\"",
"finalMethod": "最終的なメソッド",
"functionParamDefaultMissing": "パラメーター \"{name}\" に既定の引数がありません",
"functionParamName": "パラメーター名の不一致: \"{destName}\" と \"{srcName}\"",
Expand Down
Loading