mirror of
https://github.com/microsoft/pyright.git
synced 2024-09-11 16:06:39 +03:00
Added extra parse node to index expression node to allow intermediate expression type to allow for caching of index expression for both correctness and performance.
This commit is contained in:
parent
dbeafb5298
commit
0fd41aa2ef
@ -19,11 +19,11 @@ import { TextRange } from '../common/textRange';
|
||||
import { ArgumentCategory, AssignmentNode, AwaitExpressionNode,
|
||||
BinaryExpressionNode, CallExpressionNode, ClassNode, ConstantNode,
|
||||
DecoratorNode, DictionaryNode, EllipsisNode, ExpressionNode,
|
||||
IndexExpressionNode, LambdaNode, ListComprehensionNode, ListNode,
|
||||
MemberAccessExpressionNode, NameNode, NumberNode, ParameterCategory, SetNode,
|
||||
SliceExpressionNode, StarExpressionNode, StatementListNode, StringNode,
|
||||
TernaryExpressionNode, TupleExpressionNode, TypeAnnotationExpressionNode,
|
||||
UnaryExpressionNode, YieldExpressionNode } from '../parser/parseNodes';
|
||||
IndexExpressionNode, IndexItemsNode, LambdaNode, ListComprehensionNode,
|
||||
ListNode, MemberAccessExpressionNode, NameNode, NumberNode, ParameterCategory,
|
||||
SetNode, SliceExpressionNode, StarExpressionNode, StatementListNode,
|
||||
StringNode, TernaryExpressionNode, TupleExpressionNode,
|
||||
TypeAnnotationExpressionNode, UnaryExpressionNode, YieldExpressionNode } from '../parser/parseNodes';
|
||||
import { KeywordToken, KeywordType, OperatorType, QuoteTypeFlags,
|
||||
TokenType } from '../parser/tokenizerTypes';
|
||||
import { ScopeUtils } from '../scopeUtils';
|
||||
@ -694,9 +694,9 @@ export class ExpressionEvaluator {
|
||||
if (subtype.isAny()) {
|
||||
return subtype;
|
||||
} else if (subtype instanceof ClassType) {
|
||||
let typeArgs = this._getTypeArgs(node.indexExpression);
|
||||
let typeArgs = this._getTypeArgs(node.items);
|
||||
return this._createSpecializeClassType(subtype, typeArgs,
|
||||
node.indexExpression, flags);
|
||||
node.items, flags);
|
||||
} else if (subtype instanceof FunctionType) {
|
||||
// TODO - need to implement
|
||||
return UnknownType.create();
|
||||
@ -719,24 +719,15 @@ export class ExpressionEvaluator {
|
||||
}
|
||||
});
|
||||
|
||||
if (this._writeTypeToCache) {
|
||||
// Cache the type information in the index expression node as well.
|
||||
this._writeTypeToCache(node.indexExpression, type);
|
||||
}
|
||||
|
||||
return { type, node };
|
||||
}
|
||||
|
||||
private _getTypeArgs(node: ExpressionNode): TypeResult[] {
|
||||
private _getTypeArgs(node: IndexItemsNode): TypeResult[] {
|
||||
let typeArgs: TypeResult[] = [];
|
||||
|
||||
if (node instanceof TupleExpressionNode) {
|
||||
node.expressions.forEach(expr => {
|
||||
typeArgs.push(this._getTypeArg(expr));
|
||||
});
|
||||
} else {
|
||||
typeArgs.push(this._getTypeArg(node));
|
||||
}
|
||||
node.items.forEach(expr => {
|
||||
typeArgs.push(this._getTypeArg(expr));
|
||||
});
|
||||
|
||||
return typeArgs;
|
||||
}
|
||||
@ -1915,7 +1906,7 @@ export class ExpressionEvaluator {
|
||||
if (typeArgs[0].typeList) {
|
||||
typeArgs[0].typeList.forEach((entry, index) => {
|
||||
if (entry.type instanceof AnyType && entry.type.isEllipsis()) {
|
||||
this._addError(`'...' not permitted in this context`, entry.node);
|
||||
this._addError(`'...' not allowed in this context`, entry.node);
|
||||
}
|
||||
|
||||
functionType.addParameter({
|
||||
@ -1935,7 +1926,7 @@ export class ExpressionEvaluator {
|
||||
|
||||
if (typeArgs && typeArgs.length > 1) {
|
||||
if (typeArgs[1].type instanceof AnyType && typeArgs[1].type.isEllipsis()) {
|
||||
this._addError(`'...' not permitted in this context`, typeArgs[1].node);
|
||||
this._addError(`'...' not allowed in this context`, typeArgs[1].node);
|
||||
}
|
||||
functionType.setDeclaredReturnType(typeArgs[1].type);
|
||||
} else {
|
||||
@ -1957,7 +1948,7 @@ export class ExpressionEvaluator {
|
||||
}
|
||||
|
||||
if (typeArgs[0].type instanceof AnyType && typeArgs[0].type.isEllipsis()) {
|
||||
this._addError(`'...' not permitted in this context`, typeArgs[0].node);
|
||||
this._addError(`'...' not allowed in this context`, typeArgs[0].node);
|
||||
}
|
||||
|
||||
return TypeUtils.combineTypes([typeArgs[0].type, NoneType.create()]);
|
||||
|
@ -31,8 +31,9 @@ export class ExpressionUtils {
|
||||
|
||||
} else if (node.leftExpression instanceof IndexExpressionNode &&
|
||||
this._isSysVersionInfoExpression(node.leftExpression.baseExpression) &&
|
||||
node.leftExpression.indexExpression instanceof NumberNode &&
|
||||
node.leftExpression.indexExpression.token.value === 0 &&
|
||||
node.leftExpression.items.items.length === 1 &&
|
||||
node.leftExpression.items.items[0] instanceof NumberNode &&
|
||||
(node.leftExpression.items.items[0] as NumberNode).token.value === 0 &&
|
||||
node.rightExpression instanceof NumberNode) {
|
||||
|
||||
// Handle the special case of "sys.version_info[0] >= X"
|
||||
|
@ -59,7 +59,8 @@ export class ParseTreeUtils {
|
||||
')';
|
||||
} else if (node instanceof IndexExpressionNode) {
|
||||
return ParseTreeUtils.printExpression(node.baseExpression) + '[' +
|
||||
this.printExpression(node.indexExpression) + ']';
|
||||
node.items.items.map(item => this.printExpression(item)).join(', ') +
|
||||
']';
|
||||
}
|
||||
|
||||
// TODO - need to finish
|
||||
|
@ -14,14 +14,14 @@ import { ArgumentNode, AssertNode, AssignmentNode, AugmentedAssignmentExpression
|
||||
ConstantNode, ContinueNode, DecoratorNode, DelNode, DictionaryExpandEntryNode,
|
||||
DictionaryKeyEntryNode, DictionaryNode, EllipsisNode, ExceptNode,
|
||||
ForNode, FunctionNode, GlobalNode, IfNode, ImportAsNode, ImportFromAsNode,
|
||||
ImportFromNode, ImportNode, IndexExpressionNode, LambdaNode, ListComprehensionForNode,
|
||||
ListComprehensionIfNode, ListComprehensionNode, ListNode, MemberAccessExpressionNode,
|
||||
ModuleNameNode, ModuleNode, NameNode, NonlocalNode, NumberNode, ParameterNode,
|
||||
ParseNode, ParseNodeType, PassNode, RaiseNode, ReturnNode, SetNode,
|
||||
SliceExpressionNode, StarExpressionNode, StatementListNode, StringNode, SuiteNode,
|
||||
TernaryExpressionNode, TryNode, TupleExpressionNode, TypeAnnotationExpressionNode,
|
||||
UnaryExpressionNode, WhileNode, WithItemNode, WithNode,
|
||||
YieldExpressionNode, YieldFromExpressionNode } from '../parser/parseNodes';
|
||||
ImportFromNode, ImportNode, IndexExpressionNode, IndexItemsNode, LambdaNode,
|
||||
ListComprehensionForNode, ListComprehensionIfNode, ListComprehensionNode, ListNode,
|
||||
MemberAccessExpressionNode, ModuleNameNode, ModuleNode, NameNode, NonlocalNode, NumberNode,
|
||||
ParameterNode, ParseNode, ParseNodeType, PassNode, RaiseNode, ReturnNode,
|
||||
SetNode, SliceExpressionNode, StarExpressionNode, StatementListNode, StringNode,
|
||||
SuiteNode, TernaryExpressionNode, TryNode, TupleExpressionNode,
|
||||
TypeAnnotationExpressionNode, UnaryExpressionNode, WhileNode, WithItemNode,
|
||||
WithNode, YieldExpressionNode, YieldFromExpressionNode } from '../parser/parseNodes';
|
||||
|
||||
// To use this class, create a subclass and override the
|
||||
// visitXXX methods that you want to handle.
|
||||
@ -117,6 +117,9 @@ export class ParseTreeWalker {
|
||||
case ParseNodeType.Index:
|
||||
return this.visitIndex(node as IndexExpressionNode);
|
||||
|
||||
case ParseNodeType.IndexItems:
|
||||
return this.visitIndexItems(node as IndexItemsNode);
|
||||
|
||||
case ParseNodeType.Ellipsis:
|
||||
return this.visitEllipsis(node as EllipsisNode);
|
||||
|
||||
@ -329,6 +332,10 @@ export class ParseTreeWalker {
|
||||
return true;
|
||||
}
|
||||
|
||||
visitIndexItems(node: IndexItemsNode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
visitExcept(node: ExceptNode) {
|
||||
return true;
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ export enum ParseNodeType {
|
||||
ImportFrom,
|
||||
ImportFromAs,
|
||||
Index,
|
||||
IndexItems,
|
||||
Except,
|
||||
For,
|
||||
Function,
|
||||
@ -640,15 +641,14 @@ export class ListComprehensionNode<T extends ParseNode = ExpressionNode> extends
|
||||
}
|
||||
}
|
||||
|
||||
export class IndexExpressionNode extends ExpressionNode {
|
||||
readonly nodeType = ParseNodeType.Index;
|
||||
baseExpression: ExpressionNode;
|
||||
indexExpression: ExpressionNode;
|
||||
export class IndexItemsNode extends ParseNode {
|
||||
readonly nodeType = ParseNodeType.IndexItems;
|
||||
items: ExpressionNode[];
|
||||
|
||||
constructor(baseExpression: ExpressionNode, indexExpression: ExpressionNode) {
|
||||
super(baseExpression);
|
||||
this.baseExpression = baseExpression;
|
||||
this.indexExpression = indexExpression;
|
||||
constructor(openBracketToken: Token, closeBracketToken: Token, items: ExpressionNode[]) {
|
||||
super(openBracketToken);
|
||||
this.items = items;
|
||||
this.extend(closeBracketToken);
|
||||
}
|
||||
|
||||
getAssignmentError(): string | undefined {
|
||||
@ -656,7 +656,27 @@ export class IndexExpressionNode extends ExpressionNode {
|
||||
}
|
||||
|
||||
getChildren(): RecursiveParseNodeArray {
|
||||
return [this.baseExpression, this.indexExpression];
|
||||
return this.items;
|
||||
}
|
||||
}
|
||||
|
||||
export class IndexExpressionNode extends ExpressionNode {
|
||||
readonly nodeType = ParseNodeType.Index;
|
||||
baseExpression: ExpressionNode;
|
||||
items: IndexItemsNode;
|
||||
|
||||
constructor(baseExpression: ExpressionNode, items: IndexItemsNode) {
|
||||
super(baseExpression);
|
||||
this.baseExpression = baseExpression;
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
getAssignmentError(): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getChildren(): RecursiveParseNodeArray {
|
||||
return [this.baseExpression, this.items];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,14 +30,14 @@ import { ArgumentCategory, ArgumentNode, AssertNode,
|
||||
DictionaryNode, EllipsisNode, ErrorExpressionNode, ExceptNode,
|
||||
ExpressionNode, ForNode, FunctionNode, GlobalNode, IfNode, ImportAsNode,
|
||||
ImportFromAsNode, ImportFromNode, ImportNode, IndexExpressionNode,
|
||||
LambdaNode, ListComprehensionForNode, ListComprehensionIfNode, ListComprehensionIterNode,
|
||||
ListComprehensionNode, ListNode, MemberAccessExpressionNode, ModuleNameNode,
|
||||
ModuleNode, NameNode, NonlocalNode, NumberNode, ParameterCategory, ParameterNode,
|
||||
ParseNode, PassNode, RaiseNode, ReturnNode, SetNode, SliceExpressionNode,
|
||||
StarExpressionNode, StatementListNode, StatementNode, StringNode,
|
||||
SuiteNode, TernaryExpressionNode, TryNode, TupleExpressionNode, TypeAnnotationExpression,
|
||||
TypeAnnotationExpressionNode, UnaryExpressionNode, WhileNode, WithItemNode,
|
||||
WithNode, YieldExpressionNode, YieldFromExpressionNode } from './parseNodes';
|
||||
IndexItemsNode, LambdaNode, ListComprehensionForNode, ListComprehensionIfNode,
|
||||
ListComprehensionIterNode, ListComprehensionNode, ListNode, MemberAccessExpressionNode,
|
||||
ModuleNameNode, ModuleNode, NameNode, NonlocalNode, NumberNode, ParameterCategory,
|
||||
ParameterNode, ParseNode, PassNode, RaiseNode, ReturnNode, SetNode,
|
||||
SliceExpressionNode, StarExpressionNode, StatementListNode, StatementNode,
|
||||
StringNode, SuiteNode, TernaryExpressionNode, TryNode, TupleExpressionNode,
|
||||
TypeAnnotationExpression, TypeAnnotationExpressionNode, UnaryExpressionNode, WhileNode,
|
||||
WithItemNode, WithNode, YieldExpressionNode, YieldFromExpressionNode } from './parseNodes';
|
||||
import { Tokenizer, TokenizerOutput } from './tokenizer';
|
||||
import { DedentToken, IdentifierToken, KeywordToken, KeywordType,
|
||||
NumberToken, OperatorToken, OperatorType, QuoteTypeFlags, StringToken,
|
||||
@ -1592,6 +1592,8 @@ export class Parser {
|
||||
|
||||
// Consume trailers.
|
||||
while (true) {
|
||||
let nextToken = this._peekToken();
|
||||
|
||||
// Is it a function call?
|
||||
if (this._consumeTokenIfType(TokenType.OpenParenthesis)) {
|
||||
let argList = this._parseArgList();
|
||||
@ -1610,16 +1612,20 @@ export class Parser {
|
||||
} else if (this._consumeTokenIfType(TokenType.OpenBracket)) {
|
||||
// Is it an index operator?
|
||||
let indexExpr = this._parseSubscriptList();
|
||||
let indexNode = new IndexExpressionNode(atomExpression, indexExpr);
|
||||
indexNode.extend(indexNode);
|
||||
let expressions = [indexExpr];
|
||||
if (indexExpr instanceof TupleExpressionNode) {
|
||||
expressions = indexExpr.expressions;
|
||||
}
|
||||
|
||||
let nextToken = this._peekToken();
|
||||
let closingToken = this._peekToken();
|
||||
if (!this._consumeTokenIfType(TokenType.CloseBracket)) {
|
||||
return this._handleExpressionParseError('Expected "]"');
|
||||
} else {
|
||||
indexNode.extend(nextToken);
|
||||
}
|
||||
|
||||
let indexItemsNode = new IndexItemsNode(nextToken, closingToken, expressions);
|
||||
let indexNode = new IndexExpressionNode(atomExpression, indexItemsNode);
|
||||
indexNode.extend(indexNode);
|
||||
|
||||
atomExpression = indexNode;
|
||||
} else if (this._consumeTokenIfType(TokenType.Dot)) {
|
||||
// Is it a member access?
|
||||
|
Loading…
Reference in New Issue
Block a user