mirror of
https://github.com/microsoft/pyright.git
synced 2024-10-05 20:38:25 +03:00
Simplified semanticAnalyzer.
Cleaned up interface to Symbol class and added the notion of "initiallyBound". Simplified InferredType. Did some cleanup in typeAnalyzer.
This commit is contained in:
parent
f121957579
commit
e8286aa894
@ -266,9 +266,9 @@ export class CompletionProvider {
|
||||
|
||||
// Determine the kind.
|
||||
let itemKind: CompletionItemKind = CompletionItemKind.Variable;
|
||||
if (item.declarations) {
|
||||
itemKind = this._convertSymbolCategoryToItemKind(
|
||||
item.declarations[0].category);
|
||||
const declarations = item.getDeclarations();
|
||||
if (declarations.length > 0) {
|
||||
itemKind = this._convertSymbolCategoryToItemKind(declarations[0].category);
|
||||
}
|
||||
completionItem.kind = itemKind;
|
||||
completionList.items.push(completionItem);
|
||||
|
@ -20,9 +20,9 @@ import { ArgumentCategory, AssignmentNode, AwaitExpressionNode,
|
||||
BinaryExpressionNode, CallExpressionNode, ClassNode, ConstantNode,
|
||||
DecoratorNode, DictionaryExpandEntryNode, DictionaryKeyEntryNode, DictionaryNode,
|
||||
EllipsisNode, ErrorExpressionNode, ExpressionNode, IndexExpressionNode,
|
||||
IndexItemsNode, LambdaNode, ListComprehensionForNode, ListComprehensionIfNode, ListComprehensionNode,
|
||||
ListNode, MemberAccessExpressionNode, NameNode, NumberNode, ParameterCategory,
|
||||
ParseNode, SetNode, SliceExpressionNode, StatementListNode,
|
||||
IndexItemsNode, LambdaNode, ListComprehensionForNode, ListComprehensionIfNode,
|
||||
ListComprehensionNode, ListNode, MemberAccessExpressionNode, NameNode, NumberNode,
|
||||
ParameterCategory, ParseNode, SetNode, SliceExpressionNode, StatementListNode,
|
||||
StringNode, TernaryExpressionNode, TupleExpressionNode,
|
||||
TypeAnnotationExpressionNode, UnaryExpressionNode, UnpackExpressionNode,
|
||||
YieldExpressionNode, YieldFromExpressionNode } from '../parser/parseNodes';
|
||||
@ -402,8 +402,8 @@ export class ExpressionEvaluator {
|
||||
}
|
||||
});
|
||||
|
||||
classType.getClassFields().set('__init__', Symbol.create(initType, DefaultTypeSourceId));
|
||||
classType.getClassFields().set('__new__', Symbol.create(newType, DefaultTypeSourceId));
|
||||
classType.getClassFields().set('__init__', Symbol.createWithType(initType, DefaultTypeSourceId));
|
||||
classType.getClassFields().set('__new__', Symbol.createWithType(newType, DefaultTypeSourceId));
|
||||
}
|
||||
|
||||
getTypingType(symbolName: string): Type | undefined {
|
||||
@ -1711,9 +1711,7 @@ export class ExpressionEvaluator {
|
||||
// Use the cached class type and update it if this isn't the first
|
||||
// analysis path. If this is the first pass, allocate a new ClassType.
|
||||
let classType = cachedCallType as ClassType;
|
||||
if (classType) {
|
||||
assert(classType instanceof ClassType);
|
||||
} else {
|
||||
if (!(classType instanceof ClassType)) {
|
||||
classType = new ClassType(className, ClassTypeFlags.None,
|
||||
AnalyzerNodeInfo.getTypeSourceId(errorNode));
|
||||
|
||||
@ -1723,7 +1721,7 @@ export class ExpressionEvaluator {
|
||||
}
|
||||
|
||||
const classFields = classType.getClassFields();
|
||||
classFields.set('__class__', Symbol.create(classType, DefaultTypeSourceId));
|
||||
classFields.set('__class__', Symbol.createWithType(classType, DefaultTypeSourceId));
|
||||
const instanceFields = classType.getInstanceFields();
|
||||
|
||||
let builtInTupleType = ScopeUtils.getBuiltInType(this._scope, 'Tuple');
|
||||
@ -1766,7 +1764,7 @@ export class ExpressionEvaluator {
|
||||
};
|
||||
|
||||
constructorType.addParameter(paramInfo);
|
||||
instanceFields.set(entryName, Symbol.create(entryType, DefaultTypeSourceId));
|
||||
instanceFields.set(entryName, Symbol.createWithType(entryType, DefaultTypeSourceId));
|
||||
}
|
||||
});
|
||||
} else if (entriesArg.valueExpression instanceof ListNode) {
|
||||
@ -1830,7 +1828,7 @@ export class ExpressionEvaluator {
|
||||
|
||||
constructorType.addParameter(paramInfo);
|
||||
|
||||
instanceFields.set(entryName, Symbol.create(entryType, DefaultTypeSourceId));
|
||||
instanceFields.set(entryName, Symbol.createWithType(entryType, DefaultTypeSourceId));
|
||||
});
|
||||
} else {
|
||||
// A dynamic expression was used, so we can't evaluate
|
||||
@ -1852,19 +1850,19 @@ export class ExpressionEvaluator {
|
||||
initType.addParameter(selfParameter);
|
||||
TypeUtils.addDefaultFunctionParameters(initType);
|
||||
|
||||
classFields.set('__new__', Symbol.create(constructorType, DefaultTypeSourceId));
|
||||
classFields.set('__init__', Symbol.create(initType, DefaultTypeSourceId));
|
||||
classFields.set('__new__', Symbol.createWithType(constructorType, DefaultTypeSourceId));
|
||||
classFields.set('__init__', Symbol.createWithType(initType, DefaultTypeSourceId));
|
||||
|
||||
let keysItemType = new FunctionType(FunctionTypeFlags.None);
|
||||
keysItemType.setDeclaredReturnType(ScopeUtils.getBuiltInObject(this._scope, 'list',
|
||||
[ScopeUtils.getBuiltInObject(this._scope, 'str')]));
|
||||
classFields.set('keys', Symbol.create(keysItemType, DefaultTypeSourceId));
|
||||
classFields.set('items', Symbol.create(keysItemType, DefaultTypeSourceId));
|
||||
classFields.set('keys', Symbol.createWithType(keysItemType, DefaultTypeSourceId));
|
||||
classFields.set('items', Symbol.createWithType(keysItemType, DefaultTypeSourceId));
|
||||
|
||||
let lenType = new FunctionType(FunctionTypeFlags.InstanceMethod);
|
||||
lenType.setDeclaredReturnType(ScopeUtils.getBuiltInObject(this._scope, 'int'));
|
||||
lenType.addParameter(selfParameter);
|
||||
classFields.set('__len__', Symbol.create(lenType, DefaultTypeSourceId));
|
||||
classFields.set('__len__', Symbol.createWithType(lenType, DefaultTypeSourceId));
|
||||
|
||||
if (addGenericGetAttribute) {
|
||||
let getAttribType = new FunctionType(FunctionTypeFlags.InstanceMethod);
|
||||
@ -1875,7 +1873,7 @@ export class ExpressionEvaluator {
|
||||
name: 'name',
|
||||
type: ScopeUtils.getBuiltInObject(this._scope, 'str')
|
||||
});
|
||||
classFields.set('__getattribute__', Symbol.create(getAttribType, DefaultTypeSourceId));
|
||||
classFields.set('__getattribute__', Symbol.createWithType(getAttribType, DefaultTypeSourceId));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2415,8 +2413,8 @@ export class ExpressionEvaluator {
|
||||
const targetExpr = comprehension.targetExpression;
|
||||
|
||||
if (targetExpr instanceof NameNode) {
|
||||
const symbol = this._scope.addSymbol(targetExpr.nameToken.value);
|
||||
symbol.setTypeForSource(itemType, AnalyzerNodeInfo.getTypeSourceId(targetExpr));
|
||||
const symbol = this._scope.addSymbol(targetExpr.nameToken.value, false);
|
||||
symbol.setInferredTypeForSource(itemType, AnalyzerNodeInfo.getTypeSourceId(targetExpr));
|
||||
} else {
|
||||
// TODO - need to implement
|
||||
understoodType = false;
|
||||
|
@ -10,7 +10,7 @@
|
||||
* analysis proceeds.
|
||||
*/
|
||||
|
||||
import { ClassType, ObjectType, Type, UnboundType } from './types';
|
||||
import { ClassType, ObjectType, Type, UnboundType, UnknownType } from './types';
|
||||
import { TypeUtils } from './typeUtils';
|
||||
|
||||
// A type can be inferred from multiple sources. Each sources
|
||||
@ -28,7 +28,6 @@ export const DefaultTypeSourceId: TypeSourceId = 0;
|
||||
|
||||
export class InferredType {
|
||||
private _sources: InferredTypeSource[] = [];
|
||||
private _defaultType: Type;
|
||||
private _combinedType: Type;
|
||||
|
||||
// Some inferred types need to be wrapped in another
|
||||
@ -36,9 +35,8 @@ export class InferredType {
|
||||
// be wrapped in an Iterable[].
|
||||
private _genericClassWrapper: ClassType | undefined;
|
||||
|
||||
constructor(defaultType?: Type) {
|
||||
this._defaultType = defaultType || UnboundType.create();
|
||||
this._combinedType = this._defaultType;
|
||||
constructor() {
|
||||
this._combinedType = UnknownType.create();
|
||||
}
|
||||
|
||||
setGenericClassWrapper(classType: ClassType) {
|
||||
@ -114,7 +112,7 @@ export class InferredType {
|
||||
}
|
||||
|
||||
if (!newCombinedType) {
|
||||
newCombinedType = this._defaultType;
|
||||
newCombinedType = UnknownType.create();
|
||||
}
|
||||
|
||||
if (!newCombinedType.isSame(this._combinedType)) {
|
||||
|
@ -70,8 +70,8 @@ export class Scope {
|
||||
private _breaksFromLoop = false;
|
||||
|
||||
// Inferred return and yield types for the scope.
|
||||
private _returnType = new InferredType(UnknownType.create());
|
||||
private _yieldType = new InferredType(UnknownType.create());
|
||||
private _returnType = new InferredType();
|
||||
private _yieldType = new InferredType();
|
||||
|
||||
// Active type constraints for this scope -- used for conditional
|
||||
// scopes where the condition constrains the types of certain
|
||||
@ -148,8 +148,8 @@ export class Scope {
|
||||
}
|
||||
|
||||
// Adds a new untyped symbol to the scope.
|
||||
addSymbol(name: string): Symbol {
|
||||
let symbol = new Symbol();
|
||||
addSymbol(name: string, isInitiallyUnbound: boolean): Symbol {
|
||||
let symbol = new Symbol(isInitiallyUnbound);
|
||||
this._symbolTable.set(name, symbol);
|
||||
return symbol;
|
||||
}
|
||||
|
@ -22,9 +22,9 @@ import * as assert from 'assert';
|
||||
import { DiagnosticLevel } from '../common/configOptions';
|
||||
import { PythonVersion } from '../common/pythonVersion';
|
||||
import { TextRange } from '../common/textRange';
|
||||
import { AwaitExpressionNode, ClassNode, DelNode, ErrorExpressionNode,
|
||||
import { AwaitExpressionNode, ClassNode, ErrorExpressionNode,
|
||||
ExpressionNode, FunctionNode, GlobalNode, IfNode, LambdaNode, ModuleNameNode,
|
||||
ModuleNode, NameNode, NonlocalNode, RaiseNode, StringNode, SuiteNode, TryNode,
|
||||
ModuleNode, NonlocalNode, RaiseNode, StringNode, SuiteNode, TryNode,
|
||||
WhileNode, YieldExpressionNode, YieldFromExpressionNode } from '../parser/parseNodes';
|
||||
import { StringTokenFlags } from '../parser/tokenizerTypes';
|
||||
import { ScopeUtils } from '../scopeUtils';
|
||||
@ -32,7 +32,7 @@ import { AnalyzerFileInfo } from './analyzerFileInfo';
|
||||
import { AnalyzerNodeInfo } from './analyzerNodeInfo';
|
||||
import { ExpressionUtils } from './expressionUtils';
|
||||
import { ImportType } from './importResult';
|
||||
import { DefaultTypeSourceId, TypeSourceId } from './inferredType';
|
||||
import { DefaultTypeSourceId } from './inferredType';
|
||||
import { ParseTreeUtils } from './parseTreeUtils';
|
||||
import { ParseTreeWalker } from './parseTreeWalker';
|
||||
import { Scope, ScopeType } from './scope';
|
||||
@ -186,10 +186,10 @@ export abstract class SemanticAnalyzer extends ParseTreeWalker {
|
||||
});
|
||||
|
||||
if (nonMetaclassBaseClassCount === 0) {
|
||||
let objectType = ScopeUtils.getBuiltInType(this._currentScope, 'object');
|
||||
const objectType = ScopeUtils.getBuiltInType(this._currentScope, 'object');
|
||||
// Make sure we don't have 'object' derive from itself. Infinite
|
||||
// recursion will result.
|
||||
if (objectType !== classType) {
|
||||
if (!classType.isBuiltIn() || classType.getClassName() !== 'object') {
|
||||
classType.addBaseClass(objectType, false);
|
||||
}
|
||||
}
|
||||
@ -199,18 +199,16 @@ export abstract class SemanticAnalyzer extends ParseTreeWalker {
|
||||
let analyzer = new ClassScopeAnalyzer(node, this._currentScope, classType, this._fileInfo);
|
||||
this._queueSubScopeAnalyzer(analyzer);
|
||||
|
||||
// Don't bind the name of the class until after we've done the
|
||||
// first pass of its scope analysis. This guarantees that we'll flag
|
||||
// any references to the as-yet-undeclared class as an error.
|
||||
// Add the class symbol. We do this in the semantic analyzer to speed
|
||||
// up overall analysis times. Without this, the type analyzer needs
|
||||
// to do more passes to resolve classes.
|
||||
this._addSymbolToPermanentScope(node.name.nameToken.value, classType,
|
||||
AnalyzerNodeInfo.getTypeSourceId(node.name), node.name);
|
||||
AnalyzerNodeInfo.getTypeSourceId(node.name));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
visitFunction(node: FunctionNode): boolean {
|
||||
const containingClass = ParseTreeUtils.getEnclosingClass(node, true);
|
||||
|
||||
// The "__new__" magic method is not an instance method.
|
||||
// It acts as a static method instead.
|
||||
let functionFlags = FunctionTypeFlags.None;
|
||||
@ -254,11 +252,6 @@ export abstract class SemanticAnalyzer extends ParseTreeWalker {
|
||||
}
|
||||
}
|
||||
|
||||
// Use an unknown type for now since we don't do any
|
||||
// decorator processing in this pass.
|
||||
this._addSymbolToPermanentScope(node.name.nameToken.value,
|
||||
UnknownType.create(), AnalyzerNodeInfo.getTypeSourceId(node.name));
|
||||
|
||||
AnalyzerNodeInfo.setExpressionType(node, functionType);
|
||||
AnalyzerNodeInfo.setExpressionType(node.name, functionType);
|
||||
|
||||
@ -422,7 +415,7 @@ export abstract class SemanticAnalyzer extends ParseTreeWalker {
|
||||
// Don't overwrite the implicit bound names that have already
|
||||
// been added to the scope.
|
||||
if (!this._currentScope.lookUpSymbol(name)) {
|
||||
this._currentScope.addSymbol(name);
|
||||
this._currentScope.addSymbol(name, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -439,7 +432,7 @@ export abstract class SemanticAnalyzer extends ParseTreeWalker {
|
||||
// Finds the nearest permanent scope (as opposed to temporary scope) and
|
||||
// adds a new symbol with the specified name if it doesn't already exist.
|
||||
protected _addSymbolToPermanentScope(nameValue: string, type: Type,
|
||||
typeSourceId: TypeSourceId, warnIfDuplicateNode?: NameNode) {
|
||||
typeSourceId = DefaultTypeSourceId) {
|
||||
|
||||
const permanentScope = ScopeUtils.getPermanentScope(this._currentScope);
|
||||
assert(permanentScope.getType() !== ScopeType.Temporary);
|
||||
@ -447,15 +440,13 @@ export abstract class SemanticAnalyzer extends ParseTreeWalker {
|
||||
let symbol = permanentScope.lookUpSymbol(nameValue);
|
||||
|
||||
if (!symbol) {
|
||||
symbol = this._currentScope.addSymbol(nameValue);
|
||||
} else if (warnIfDuplicateNode) {
|
||||
if (symbol.inferredType.getSourceCount() > 0) {
|
||||
this._fileInfo.diagnosticSink.addWarningWithTextRange(
|
||||
`'${ nameValue }' is already defined`, warnIfDuplicateNode);
|
||||
}
|
||||
// Add the symbol. Assume that symbols with a default type source ID
|
||||
// are "implicit" symbols added to the scope. These are not initially unbound.
|
||||
symbol = this._currentScope.addSymbol(nameValue,
|
||||
typeSourceId !== DefaultTypeSourceId);
|
||||
}
|
||||
|
||||
symbol.inferredType.addSource(type, typeSourceId);
|
||||
symbol.setInferredTypeForSource(type, typeSourceId);
|
||||
}
|
||||
|
||||
private _validateYieldUsage(node: YieldExpressionNode | YieldFromExpressionNode) {
|
||||
@ -548,19 +539,14 @@ export class ModuleScopeAnalyzer extends SemanticAnalyzer {
|
||||
private _bindImplicitNames() {
|
||||
// List taken from https://docs.python.org/3/reference/import.html#__name__
|
||||
this._addSymbolToPermanentScope('__name__',
|
||||
ScopeUtils.getBuiltInObject(this._currentScope, 'str'), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__loader__',
|
||||
AnyType.create(), DefaultTypeSourceId);
|
||||
ScopeUtils.getBuiltInObject(this._currentScope, 'str'));
|
||||
this._addSymbolToPermanentScope('__loader__', AnyType.create());
|
||||
this._addSymbolToPermanentScope('__package__',
|
||||
ScopeUtils.getBuiltInObject(this._currentScope, 'str'), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__spec__',
|
||||
AnyType.create(), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__path__',
|
||||
ScopeUtils.getBuiltInObject(this._currentScope, 'str'), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__file__',
|
||||
ScopeUtils.getBuiltInObject(this._currentScope, 'str'), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__cached__',
|
||||
ScopeUtils.getBuiltInObject(this._currentScope, 'str'), DefaultTypeSourceId);
|
||||
ScopeUtils.getBuiltInObject(this._currentScope, 'str'));
|
||||
this._addSymbolToPermanentScope('__spec__', AnyType.create());
|
||||
this._addSymbolToPermanentScope('__path__', ScopeUtils.getBuiltInObject(this._currentScope, 'str'));
|
||||
this._addSymbolToPermanentScope('__file__', ScopeUtils.getBuiltInObject(this._currentScope, 'str'));
|
||||
this._addSymbolToPermanentScope('__cached__', ScopeUtils.getBuiltInObject(this._currentScope, 'str'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -595,14 +581,10 @@ export class ClassScopeAnalyzer extends SemanticAnalyzer {
|
||||
private _bindImplicitNames() {
|
||||
let classType = AnalyzerNodeInfo.getExpressionType(this._scopedNode);
|
||||
assert(classType instanceof ClassType);
|
||||
this._addSymbolToPermanentScope('__class__',
|
||||
classType!, DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__dict__',
|
||||
AnyType.create(), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__doc__',
|
||||
ScopeUtils.getBuiltInObject(this._currentScope, 'str'), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__name__',
|
||||
ScopeUtils.getBuiltInObject(this._currentScope, 'str'), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__class__', classType!);
|
||||
this._addSymbolToPermanentScope('__dict__', AnyType.create());
|
||||
this._addSymbolToPermanentScope('__doc__', ScopeUtils.getBuiltInObject(this._currentScope, 'str'));
|
||||
this._addSymbolToPermanentScope('__name__', ScopeUtils.getBuiltInObject(this._currentScope, 'str'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -636,30 +618,19 @@ export class FunctionScopeAnalyzer extends SemanticAnalyzer {
|
||||
|
||||
private _bindImplicitNames() {
|
||||
// List taken from https://docs.python.org/3/reference/datamodel.html
|
||||
this._addSymbolToPermanentScope('__doc__',
|
||||
ScopeUtils.getBuiltInObject(this._currentScope, 'str'), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__name__',
|
||||
ScopeUtils.getBuiltInObject(this._currentScope, 'str'), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__doc__', ScopeUtils.getBuiltInObject(this._currentScope, 'str'));
|
||||
this._addSymbolToPermanentScope('__name__', ScopeUtils.getBuiltInObject(this._currentScope, 'str'));
|
||||
if (this._fileInfo.executionEnvironment.pythonVersion >= PythonVersion.V33) {
|
||||
this._addSymbolToPermanentScope('__qualname__',
|
||||
ScopeUtils.getBuiltInObject(this._currentScope, 'str'), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__qualname__', ScopeUtils.getBuiltInObject(this._currentScope, 'str'));
|
||||
}
|
||||
this._addSymbolToPermanentScope('__module__',
|
||||
ScopeUtils.getBuiltInObject(this._currentScope, 'str'), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__defaults__',
|
||||
AnyType.create(), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__code__',
|
||||
AnyType.create(), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__globals__',
|
||||
AnyType.create(), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__dict__',
|
||||
AnyType.create(), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__closure__',
|
||||
AnyType.create(), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__annotations__',
|
||||
AnyType.create(), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__kwdefaults__',
|
||||
AnyType.create(), DefaultTypeSourceId);
|
||||
this._addSymbolToPermanentScope('__module__', ScopeUtils.getBuiltInObject(this._currentScope, 'str'));
|
||||
this._addSymbolToPermanentScope('__defaults__', AnyType.create());
|
||||
this._addSymbolToPermanentScope('__code__', AnyType.create());
|
||||
this._addSymbolToPermanentScope('__globals__', AnyType.create());
|
||||
this._addSymbolToPermanentScope('__dict__', AnyType.create());
|
||||
this._addSymbolToPermanentScope('__closure__', AnyType.create());
|
||||
this._addSymbolToPermanentScope('__annotations__', AnyType.create());
|
||||
this._addSymbolToPermanentScope('__kwdefaults__', AnyType.create());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,45 +43,73 @@ export interface Declaration {
|
||||
|
||||
export class Symbol {
|
||||
// Inferred type of the symbol.
|
||||
inferredType: InferredType = new InferredType();
|
||||
private _inferredType: InferredType = new InferredType();
|
||||
|
||||
// Information about the node that declared the value -
|
||||
// i.e. where the editor will take the user if "show definition"
|
||||
// is selected. Multiple declarations can exist for variables,
|
||||
// properties, and functions (in the case of @overload).
|
||||
declarations?: Declaration[];
|
||||
private _declarations?: Declaration[];
|
||||
|
||||
static create(type: Type, typeSourceId: TypeSourceId) {
|
||||
const newSymbol = new Symbol();
|
||||
newSymbol.setTypeForSource(type, typeSourceId);
|
||||
// Indicates that the symbol is initially unbound and can
|
||||
// later be unbound through a delete operation.
|
||||
private _isInitiallyUnbound: boolean;
|
||||
|
||||
constructor(isInitiallyUnbound: boolean) {
|
||||
this._isInitiallyUnbound = isInitiallyUnbound;
|
||||
}
|
||||
|
||||
static createWithType(type: Type, typeSourceId: TypeSourceId) {
|
||||
const newSymbol = new Symbol(true);
|
||||
newSymbol.setInferredTypeForSource(type, typeSourceId);
|
||||
return newSymbol;
|
||||
}
|
||||
|
||||
isInitiallyUnbound() {
|
||||
return this._isInitiallyUnbound;
|
||||
}
|
||||
|
||||
// Returns true if inferred type changed.
|
||||
setTypeForSource(type: Type, typeSourceId: TypeSourceId): boolean {
|
||||
return this.inferredType.addSource(type, typeSourceId);
|
||||
setInferredTypeForSource(type: Type, typeSourceId: TypeSourceId): boolean {
|
||||
return this._inferredType.addSource(type, typeSourceId);
|
||||
}
|
||||
|
||||
getInferredType() {
|
||||
return this._inferredType.getType();
|
||||
}
|
||||
|
||||
addDeclaration(declaration: Declaration) {
|
||||
if (this.declarations) {
|
||||
if (this._declarations) {
|
||||
// See if this node was already identified as a declaration. If so,
|
||||
// replace it. Otherwise, add it as a new declaration to the end of
|
||||
// the list.
|
||||
let declIndex = this.declarations.findIndex(decl => decl.node === declaration.node);
|
||||
let declIndex = this._declarations.findIndex(decl => decl.node === declaration.node);
|
||||
if (declIndex >= 0) {
|
||||
// This declaration has already been added. Update the declared
|
||||
// type if it's available. The other fields in the declaration
|
||||
// should be the same from one analysis pass to the next.
|
||||
if (declaration.declaredType) {
|
||||
this.declarations[declIndex].declaredType = declaration.declaredType;
|
||||
this._declarations[declIndex].declaredType = declaration.declaredType;
|
||||
}
|
||||
} else {
|
||||
this.declarations.push(declaration);
|
||||
this._declarations.push(declaration);
|
||||
}
|
||||
} else {
|
||||
this.declarations = [declaration];
|
||||
this._declarations = [declaration];
|
||||
}
|
||||
}
|
||||
|
||||
getDeclarationCount() {
|
||||
return this._declarations ? this._declarations.length : 0;
|
||||
}
|
||||
|
||||
hasDeclarations() {
|
||||
return this.getDeclarationCount() > 0;
|
||||
}
|
||||
|
||||
getDeclarations() {
|
||||
return this._declarations ? this._declarations : [];
|
||||
}
|
||||
}
|
||||
|
||||
// Maps names to symbol information.
|
||||
|
@ -335,7 +335,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
}
|
||||
} else {
|
||||
// There is no annotation, and we can't infer the type.
|
||||
if (param.name && param.category === ParameterCategory.Simple) {
|
||||
if (param.name) {
|
||||
this._addDiagnostic(this._fileInfo.configOptions.reportUnknownParameterType,
|
||||
`Type of '${ param.name.nameToken.value }' is unknown`,
|
||||
param.name);
|
||||
@ -519,10 +519,10 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
// Cache the type for the hover provider.
|
||||
this._getTypeOfExpression(param.name);
|
||||
|
||||
// Set the declaration on the node for the definition language service.
|
||||
// Set the declaration on the node for the definition provider.
|
||||
const symbol = this._currentScope.lookUpSymbol(param.name.nameToken.value);
|
||||
if (symbol && symbol.declarations) {
|
||||
AnalyzerNodeInfo.setDeclaration(param.name, symbol.declarations[0]);
|
||||
if (symbol && symbol.hasDeclarations()) {
|
||||
AnalyzerNodeInfo.setDeclaration(param.name, symbol.getDeclarations()[0]);
|
||||
}
|
||||
|
||||
let declaration: Declaration | undefined;
|
||||
@ -907,120 +907,8 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
visitAssignment(node: AssignmentNode): boolean {
|
||||
// Special-case the typing.pyi file, which contains some special
|
||||
// types that the type analyzer needs to interpret differently.
|
||||
if (this._fileInfo.isTypingStubFile) {
|
||||
if (node.leftExpression instanceof NameNode) {
|
||||
const assignedName = node.leftExpression.nameToken.value;
|
||||
let specialType: Type | undefined;
|
||||
|
||||
if (assignedName === 'Any') {
|
||||
specialType = AnyType.create();
|
||||
} else {
|
||||
const specialTypes = ['overload', 'TypeVar', '_promote', 'no_type_check',
|
||||
'NoReturn', 'Union', 'Optional', 'List', 'Dict', 'DefaultDict',
|
||||
'Set', 'FrozenSet', 'Deque', 'ChainMap'];
|
||||
if (specialTypes.find(t => t === assignedName)) {
|
||||
const aliasMap: { [name: string]: AliasMapEntry } = {
|
||||
'List': { alias: 'list', module: 'builtins' },
|
||||
'Dict': { alias: 'dict', module: 'builtins' },
|
||||
'DefaultDict': { alias: 'defaultdict', module: 'collections' },
|
||||
'Set': { alias: 'set', module: 'builtins' },
|
||||
'FrozenSet': { alias: 'frozenset', module: 'builtins' },
|
||||
'Deque': { alias: 'deque', module: 'collections' },
|
||||
'ChainMap': { alias: 'ChainMap', module: 'collections' }
|
||||
};
|
||||
|
||||
// Synthesize a class.
|
||||
let specialClassType = new ClassType(assignedName,
|
||||
ClassTypeFlags.BuiltInClass | ClassTypeFlags.SpecialBuiltIn,
|
||||
DefaultTypeSourceId);
|
||||
|
||||
// See if we need to locate an alias class to bind it to.
|
||||
const aliasMapEntry = aliasMap[assignedName];
|
||||
if (aliasMapEntry) {
|
||||
let aliasClass: Type | undefined;
|
||||
const aliasName = aliasMapEntry.alias;
|
||||
|
||||
if (aliasMapEntry.module === 'builtins') {
|
||||
aliasClass = ScopeUtils.getBuiltInType(this._currentScope, aliasName);
|
||||
} else if (aliasMapEntry.module === 'collections') {
|
||||
// The typing.pyi file imports collections.
|
||||
let collectionsScope = this._findCollectionsImportScope();
|
||||
if (collectionsScope) {
|
||||
const symbolInfo = collectionsScope.lookUpSymbol(aliasName);
|
||||
if (symbolInfo) {
|
||||
aliasClass = TypeUtils.getEffectiveTypeOfSymbol(symbolInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aliasClass instanceof ClassType) {
|
||||
specialClassType.addBaseClass(aliasClass, false);
|
||||
specialClassType.setAliasClass(aliasClass);
|
||||
}
|
||||
}
|
||||
|
||||
specialType = specialClassType;
|
||||
}
|
||||
}
|
||||
|
||||
if (specialType) {
|
||||
let declaration: Declaration = {
|
||||
category: SymbolCategory.Class,
|
||||
node: node.leftExpression,
|
||||
path: this._fileInfo.filePath,
|
||||
range: convertOffsetsToRange(node.leftExpression.start,
|
||||
node.leftExpression.end, this._fileInfo.lines)
|
||||
};
|
||||
this._assignTypeToNameNode(node.leftExpression, specialType, declaration);
|
||||
this._updateExpressionTypeForNode(node.leftExpression, specialType);
|
||||
return false;
|
||||
}
|
||||
} else if (node.leftExpression instanceof TypeAnnotationExpressionNode &&
|
||||
node.leftExpression.valueExpression instanceof NameNode) {
|
||||
|
||||
const nameNode = node.leftExpression.valueExpression;
|
||||
const assignedName = nameNode.nameToken.value;
|
||||
let specialType: Type | undefined;
|
||||
|
||||
const specialTypes = ['Tuple', 'Generic', 'Protocol', 'Callable',
|
||||
'Type', 'ClassVar', 'Final', 'Literal'];
|
||||
if (specialTypes.find(t => t === assignedName)) {
|
||||
// Synthesize a class.
|
||||
let specialClassType = new ClassType(assignedName,
|
||||
ClassTypeFlags.BuiltInClass | ClassTypeFlags.SpecialBuiltIn,
|
||||
AnalyzerNodeInfo.getTypeSourceId(node));
|
||||
|
||||
let aliasClass = ScopeUtils.getBuiltInType(this._currentScope,
|
||||
assignedName.toLowerCase());
|
||||
if (aliasClass instanceof ClassType) {
|
||||
specialClassType.setAliasClass(aliasClass);
|
||||
|
||||
let specializedBaseClass = TypeUtils.specializeType(aliasClass, undefined);
|
||||
specialClassType.addBaseClass(specializedBaseClass, false);
|
||||
} else {
|
||||
// The other classes derive from 'object'.
|
||||
let objBaseClass = ScopeUtils.getBuiltInType(this._currentScope, 'object');
|
||||
if (objBaseClass instanceof ClassType) {
|
||||
specialClassType.addBaseClass(objBaseClass, false);
|
||||
}
|
||||
}
|
||||
|
||||
specialType = specialClassType;
|
||||
}
|
||||
|
||||
if (specialType) {
|
||||
let declaration: Declaration = {
|
||||
category: SymbolCategory.Class,
|
||||
node: nameNode,
|
||||
path: this._fileInfo.filePath,
|
||||
range: convertOffsetsToRange(nameNode.start,
|
||||
nameNode.end, this._fileInfo.lines)
|
||||
};
|
||||
this._assignTypeToNameNode(nameNode, specialType, declaration);
|
||||
this._updateExpressionTypeForNode(nameNode, specialType);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (this._handleTypingStubAssignment(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let valueType = this._getTypeOfExpression(node.rightExpression);
|
||||
@ -1134,7 +1022,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
// If there's no declaration assigned to this name node, assign one
|
||||
// for the hover provider.
|
||||
if (!AnalyzerNodeInfo.getDeclaration(node)) {
|
||||
if (symbolInScope && symbolInScope.symbol.declarations) {
|
||||
if (symbolInScope && symbolInScope.symbol.hasDeclarations()) {
|
||||
AnalyzerNodeInfo.setDeclaration(node,
|
||||
TypeUtils.getPrimaryDeclarationOfSymbol(symbolInScope.symbol)!);
|
||||
}
|
||||
@ -1189,8 +1077,8 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
if (expr instanceof NameNode) {
|
||||
let symbolWithScope = this._currentScope.lookUpSymbolRecursive(expr.nameToken.value);
|
||||
if (symbolWithScope) {
|
||||
if (symbolWithScope.symbol.declarations) {
|
||||
const category = symbolWithScope.symbol.declarations[0].category;
|
||||
if (symbolWithScope.symbol.hasDeclarations()) {
|
||||
const category = symbolWithScope.symbol.getDeclarations()[0].category;
|
||||
if (category === SymbolCategory.Function || category === SymbolCategory.Method) {
|
||||
this._addError('Del should not be applied to function', expr);
|
||||
} else if (category === SymbolCategory.Class) {
|
||||
@ -1247,8 +1135,8 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
range: { start: { line: 0, column: 0 }, end: { line: 0, column: 0 }}
|
||||
};
|
||||
|
||||
let newSymbol = Symbol.create(implicitModuleType, DefaultTypeSourceId);
|
||||
newSymbol.declarations = [declaration];
|
||||
let newSymbol = Symbol.createWithType(implicitModuleType, DefaultTypeSourceId);
|
||||
newSymbol.addDeclaration(declaration);
|
||||
moduleFields.set(implicitImport.name, newSymbol);
|
||||
}
|
||||
}
|
||||
@ -1305,9 +1193,9 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
const moduleFields = moduleType.getFields();
|
||||
moduleFields.forEach((boundValue, fieldName) => {
|
||||
this._addSymbolToPermanentScope(fieldName);
|
||||
this._addTypeSourceToName(fieldName, boundValue.inferredType.getType(),
|
||||
this._addTypeSourceToName(fieldName, TypeUtils.getEffectiveTypeOfSymbol(boundValue),
|
||||
AnalyzerNodeInfo.getTypeSourceId(node),
|
||||
boundValue.declarations ? boundValue.declarations[0] : undefined);
|
||||
boundValue.hasDeclarations() ? boundValue.getDeclarations()[0] : undefined);
|
||||
});
|
||||
|
||||
// Import the fields in the current permanent scope.
|
||||
@ -1325,7 +1213,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
const name = importAs.name.nameToken.value;
|
||||
let symbolType: Type | undefined;
|
||||
const aliasNode = importAs.alias || importAs.name;
|
||||
let declaration: Declaration | undefined;
|
||||
let declarations: Declaration[] = [];
|
||||
|
||||
// Is the name referring to an implicit import?
|
||||
let implicitImport = importInfo!.implicitImports.find(impImport => impImport.name === name);
|
||||
@ -1336,8 +1224,11 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
this._fileInfo.importMap[implicitImport.path].parseTree) {
|
||||
|
||||
symbolType = moduleType;
|
||||
declaration = AnalyzerNodeInfo.getDeclaration(
|
||||
const moduleDecl = AnalyzerNodeInfo.getDeclaration(
|
||||
this._fileInfo.importMap[implicitImport.path].parseTree);
|
||||
if (moduleDecl) {
|
||||
declarations = [moduleDecl];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let moduleType = this._getModuleTypeForImportPath(importInfo, resolvedPath);
|
||||
@ -1346,8 +1237,8 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
const symbol = moduleFields.get(name);
|
||||
if (symbol) {
|
||||
symbolType = TypeUtils.getEffectiveTypeOfSymbol(symbol);
|
||||
if (symbol.declarations) {
|
||||
declaration = symbol.declarations[0];
|
||||
if (symbol.hasDeclarations()) {
|
||||
declarations = symbol.getDeclarations();
|
||||
}
|
||||
} else {
|
||||
this._addError(
|
||||
@ -1367,14 +1258,15 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
this._updateExpressionTypeForNode(importAs.alias, symbolType);
|
||||
}
|
||||
|
||||
if (declaration) {
|
||||
AnalyzerNodeInfo.setDeclaration(importAs.name, declaration);
|
||||
if (declarations.length > 0) {
|
||||
AnalyzerNodeInfo.setDeclaration(importAs.name, declarations[0]);
|
||||
if (importAs.alias) {
|
||||
AnalyzerNodeInfo.setDeclaration(importAs.name, declaration);
|
||||
AnalyzerNodeInfo.setDeclaration(importAs.name, declarations[0]);
|
||||
}
|
||||
}
|
||||
|
||||
this._assignTypeToNameNode(aliasNode, symbolType, declaration);
|
||||
this._assignTypeToNameNode(aliasNode, symbolType,
|
||||
declarations.length > 0 ? declarations[0] : undefined);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@ -1452,6 +1344,141 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handles some special-case assignment statements that are found
|
||||
// within the typings.pyi file.
|
||||
private _handleTypingStubAssignment(node: AssignmentNode): boolean {
|
||||
if (!this._fileInfo.isTypingStubFile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node.leftExpression instanceof NameNode) {
|
||||
const assignedName = node.leftExpression.nameToken.value;
|
||||
let specialType: Type | undefined;
|
||||
|
||||
if (assignedName === 'Any') {
|
||||
specialType = AnyType.create();
|
||||
} else {
|
||||
const specialTypes = ['overload', 'TypeVar', '_promote', 'no_type_check',
|
||||
'NoReturn', 'Union', 'Optional', 'List', 'Dict', 'DefaultDict',
|
||||
'Set', 'FrozenSet', 'Deque', 'ChainMap'];
|
||||
if (specialTypes.find(t => t === assignedName)) {
|
||||
const aliasMap: { [name: string]: AliasMapEntry } = {
|
||||
'List': { alias: 'list', module: 'builtins' },
|
||||
'Dict': { alias: 'dict', module: 'builtins' },
|
||||
'DefaultDict': { alias: 'defaultdict', module: 'collections' },
|
||||
'Set': { alias: 'set', module: 'builtins' },
|
||||
'FrozenSet': { alias: 'frozenset', module: 'builtins' },
|
||||
'Deque': { alias: 'deque', module: 'collections' },
|
||||
'ChainMap': { alias: 'ChainMap', module: 'collections' }
|
||||
};
|
||||
|
||||
// Synthesize a class.
|
||||
const specialClassType = new ClassType(assignedName,
|
||||
ClassTypeFlags.BuiltInClass | ClassTypeFlags.SpecialBuiltIn,
|
||||
DefaultTypeSourceId);
|
||||
|
||||
// See if we need to locate an alias class to bind it to.
|
||||
const aliasMapEntry = aliasMap[assignedName];
|
||||
if (aliasMapEntry) {
|
||||
let aliasClass: Type | undefined;
|
||||
const aliasName = aliasMapEntry.alias;
|
||||
|
||||
if (aliasMapEntry.module === 'builtins') {
|
||||
aliasClass = ScopeUtils.getBuiltInType(this._currentScope, aliasName);
|
||||
} else if (aliasMapEntry.module === 'collections') {
|
||||
// The typing.pyi file imports collections.
|
||||
let collectionsScope = this._findCollectionsImportScope();
|
||||
if (collectionsScope) {
|
||||
const symbolInfo = collectionsScope.lookUpSymbol(aliasName);
|
||||
if (symbolInfo) {
|
||||
aliasClass = TypeUtils.getEffectiveTypeOfSymbol(symbolInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aliasClass instanceof ClassType) {
|
||||
specialClassType.addBaseClass(aliasClass, false);
|
||||
specialClassType.setAliasClass(aliasClass);
|
||||
specialType = specialClassType;
|
||||
} else {
|
||||
// The alias class has not yet been created. Use an unknown
|
||||
// type and hope that in the next analysis pass we'll get
|
||||
// the real type.
|
||||
specialType = UnknownType.create();
|
||||
}
|
||||
} else {
|
||||
specialType = specialClassType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (specialType) {
|
||||
let declaration: Declaration = {
|
||||
category: SymbolCategory.Class,
|
||||
node: node.leftExpression,
|
||||
path: this._fileInfo.filePath,
|
||||
range: convertOffsetsToRange(node.leftExpression.start,
|
||||
node.leftExpression.end, this._fileInfo.lines)
|
||||
};
|
||||
this._assignTypeToNameNode(node.leftExpression, specialType, declaration);
|
||||
this._updateExpressionTypeForNode(node.leftExpression, specialType);
|
||||
return true;
|
||||
}
|
||||
} else if (node.leftExpression instanceof TypeAnnotationExpressionNode &&
|
||||
node.leftExpression.valueExpression instanceof NameNode) {
|
||||
|
||||
const nameNode = node.leftExpression.valueExpression;
|
||||
const assignedName = nameNode.nameToken.value;
|
||||
let specialType: Type | undefined;
|
||||
|
||||
const specialTypes = ['Tuple', 'Generic', 'Protocol', 'Callable',
|
||||
'Type', 'ClassVar', 'Final', 'Literal'];
|
||||
if (specialTypes.find(t => t === assignedName)) {
|
||||
// Synthesize a class.
|
||||
const specialClassType = new ClassType(assignedName,
|
||||
ClassTypeFlags.BuiltInClass | ClassTypeFlags.SpecialBuiltIn,
|
||||
AnalyzerNodeInfo.getTypeSourceId(node));
|
||||
|
||||
const aliasClass = ScopeUtils.getBuiltInType(this._currentScope,
|
||||
assignedName.toLowerCase());
|
||||
if (aliasClass instanceof ClassType) {
|
||||
specialClassType.setAliasClass(aliasClass);
|
||||
|
||||
const specializedBaseClass = TypeUtils.specializeType(aliasClass, undefined);
|
||||
specialClassType.addBaseClass(specializedBaseClass, false);
|
||||
specialType = specialClassType;
|
||||
} else {
|
||||
// The other classes derive from 'object'.
|
||||
const objBaseClass = ScopeUtils.getBuiltInType(this._currentScope, 'object');
|
||||
if (objBaseClass instanceof ClassType) {
|
||||
specialClassType.addBaseClass(objBaseClass, false);
|
||||
specialType = specialClassType;
|
||||
} else {
|
||||
// The base class has not yet been created. Use an unknown
|
||||
// type and hope that in the next analysis pass we'll get
|
||||
// the real type.
|
||||
specialType = UnknownType.create();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (specialType) {
|
||||
let declaration: Declaration = {
|
||||
category: SymbolCategory.Class,
|
||||
node: nameNode,
|
||||
path: this._fileInfo.filePath,
|
||||
range: convertOffsetsToRange(nameNode.start,
|
||||
nameNode.end, this._fileInfo.lines)
|
||||
};
|
||||
this._assignTypeToNameNode(nameNode, specialType, declaration);
|
||||
this._updateExpressionTypeForNode(nameNode, specialType);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Transforms the parameter type based on its category. If it's a simple parameter,
|
||||
// no transform is applied. If it's a var-arg or keword-arg parameter, the type
|
||||
// is wrapped in a List or Dict.
|
||||
@ -1562,8 +1589,9 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
|
||||
private _addDeclarationToSymbol(symbol: Symbol, declaration: Declaration, errorNode: ExpressionNode) {
|
||||
// Are we adding a new declaration with a declared type?
|
||||
if (symbol.declarations && declaration.declaredType) {
|
||||
const declWithDefinedType = symbol.declarations.find(decl => !!decl.declaredType);
|
||||
const prevDeclarations = symbol.getDeclarations();
|
||||
if (prevDeclarations.length > 0 && declaration.declaredType) {
|
||||
const declWithDefinedType = prevDeclarations.find(decl => !!decl.declaredType);
|
||||
|
||||
if (declWithDefinedType && declaration.node !== declWithDefinedType.node) {
|
||||
// If we're adding a declaration, make sure it's the same type as an existing declaration.
|
||||
@ -2175,7 +2203,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
// to generate two sources because the types may different, and the analysis
|
||||
// won't converge if we use the same source ID for both.
|
||||
const sourceId = AnalyzerNodeInfo.getTypeSourceId(typeAnnotationNode || node.memberName);
|
||||
if (symbol.setTypeForSource(typeOfExpr, sourceId)) {
|
||||
if (symbol.setInferredTypeForSource(typeOfExpr, sourceId)) {
|
||||
this._setAnalysisChanged();
|
||||
}
|
||||
|
||||
@ -2193,9 +2221,9 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
// name, but there's also now an instance variable introduced. Combine the
|
||||
// type of the class variable with that of the new instance variable.
|
||||
if (memberInfo.symbol && !memberInfo.isInstanceMember && isInstanceMember) {
|
||||
if (memberInfo.symbol.declarations) {
|
||||
inheritedDeclaration = memberInfo.symbol.declarations.find(decl => !!decl.declaredType);
|
||||
// declaredType = TypeUtils.getDeclaredTypeOfSymbol(memberInfo.symbol);
|
||||
const prevDeclarations = memberInfo.symbol.getDeclarations();
|
||||
if (prevDeclarations.length > 0) {
|
||||
inheritedDeclaration = prevDeclarations.find(decl => !!decl.declaredType);
|
||||
}
|
||||
|
||||
typeOfExpr = TypeUtils.combineTypes([typeOfExpr, memberInfo.symbolType]);
|
||||
@ -2208,7 +2236,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
}
|
||||
|
||||
if (addNewMemberToLocalClass) {
|
||||
let newSymbol = Symbol.create(typeOfExpr, AnalyzerNodeInfo.getTypeSourceId(node.memberName));
|
||||
let newSymbol = Symbol.createWithType(typeOfExpr, AnalyzerNodeInfo.getTypeSourceId(node.memberName));
|
||||
|
||||
// If this is an instance variable that has a corresponding class varible
|
||||
// with a defined type, it should inherit that declaration (and declared type).
|
||||
@ -2313,7 +2341,8 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
let implicitModuleType = this._getModuleTypeForImportPath(
|
||||
undefined, implicitImport.path);
|
||||
if (implicitModuleType) {
|
||||
symbolTable.set(implicitImport.name, Symbol.create(implicitModuleType, DefaultTypeSourceId));
|
||||
symbolTable.set(implicitImport.name, Symbol.createWithType(
|
||||
implicitModuleType, DefaultTypeSourceId));
|
||||
}
|
||||
});
|
||||
|
||||
@ -2504,7 +2533,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
|
||||
private _addNamedTargetToCurrentScope(node: ExpressionNode) {
|
||||
if (node instanceof NameNode) {
|
||||
this._currentScope.addSymbol(node.nameToken.value);
|
||||
this._currentScope.addSymbol(node.nameToken.value, true);
|
||||
} else if (node instanceof TypeAnnotationExpressionNode) {
|
||||
this._addNamedTargetToCurrentScope(node.valueExpression);
|
||||
} else if (node instanceof TupleExpressionNode) {
|
||||
@ -2521,7 +2550,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
private _bindMultiPartModuleNameToType(nameParts: NameNode[], type: ModuleType,
|
||||
declaration?: Declaration): void {
|
||||
let targetSymbolTable = this._currentScope.getSymbolTable();
|
||||
let symbol = Symbol.create(type, DefaultTypeSourceId);
|
||||
let symbol = Symbol.createWithType(type, DefaultTypeSourceId);
|
||||
if (declaration) {
|
||||
symbol.addDeclaration(declaration);
|
||||
}
|
||||
@ -2557,7 +2586,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
// to the next part of the name.
|
||||
let newPartialModule = new ModuleType(new SymbolTable());
|
||||
newPartialModule.setIsPartialModule();
|
||||
targetSymbolTable.set(name, Symbol.create(newPartialModule, DefaultTypeSourceId));
|
||||
targetSymbolTable.set(name, Symbol.createWithType(newPartialModule, DefaultTypeSourceId));
|
||||
targetSymbolTable = newPartialModule.getFields();
|
||||
}
|
||||
}
|
||||
@ -2573,13 +2602,9 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
|
||||
const symbolWithScope = this._currentScope.lookUpSymbolRecursive(nameValue);
|
||||
if (symbolWithScope) {
|
||||
if (symbolWithScope.symbol.declarations) {
|
||||
const declWithDefinedType = symbolWithScope.symbol.declarations.find(
|
||||
decl => !!decl.declaredType);
|
||||
|
||||
if (declWithDefinedType) {
|
||||
declaredType = declWithDefinedType.declaredType!;
|
||||
}
|
||||
const primaryDecl = TypeUtils.getPrimaryDeclarationOfSymbol(symbolWithScope.symbol);
|
||||
if (primaryDecl) {
|
||||
declaredType = primaryDecl.declaredType!;
|
||||
}
|
||||
} else {
|
||||
// We should never get here.
|
||||
@ -2610,7 +2635,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
assert(permanentScope.getType() !== ScopeType.Temporary);
|
||||
|
||||
if (!permanentScope.lookUpSymbol(name)) {
|
||||
permanentScope.addSymbol(name);
|
||||
permanentScope.addSymbol(name, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2626,7 +2651,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
|
||||
const symbolWithScope = this._currentScope.lookUpSymbolRecursive(name);
|
||||
if (symbolWithScope) {
|
||||
if (symbolWithScope.symbol.inferredType.addSource(type, typeSourceId)) {
|
||||
if (symbolWithScope.symbol.setInferredTypeForSource(type, typeSourceId)) {
|
||||
if (symbolWithScope.scope.getType() !== ScopeType.Temporary) {
|
||||
this._setAnalysisChanged();
|
||||
}
|
||||
@ -2699,21 +2724,21 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
let classMemberInfo = TypeUtils.lookUpClassMember(
|
||||
baseType.getClassType(), memberNameValue);
|
||||
if (classMemberInfo) {
|
||||
if (classMemberInfo.symbol && classMemberInfo.symbol.declarations) {
|
||||
if (classMemberInfo.symbol && classMemberInfo.symbol.hasDeclarations()) {
|
||||
AnalyzerNodeInfo.setDeclaration(memberName,
|
||||
TypeUtils.getPrimaryDeclarationOfSymbol(classMemberInfo.symbol)!);
|
||||
}
|
||||
}
|
||||
} else if (baseType instanceof ModuleType) {
|
||||
let moduleMemberInfo = baseType.getFields().get(memberNameValue);
|
||||
if (moduleMemberInfo && moduleMemberInfo.declarations) {
|
||||
if (moduleMemberInfo && moduleMemberInfo.hasDeclarations()) {
|
||||
AnalyzerNodeInfo.setDeclaration(memberName,
|
||||
TypeUtils.getPrimaryDeclarationOfSymbol(moduleMemberInfo)!);
|
||||
}
|
||||
} else if (baseType instanceof ClassType) {
|
||||
let classMemberInfo = TypeUtils.lookUpClassMember(baseType, memberNameValue,
|
||||
ClassMemberLookupFlags.SkipInstanceVariables);
|
||||
if (classMemberInfo && classMemberInfo.symbol && classMemberInfo.symbol.declarations) {
|
||||
if (classMemberInfo && classMemberInfo.symbol && classMemberInfo.symbol.hasDeclarations()) {
|
||||
AnalyzerNodeInfo.setDeclaration(memberName,
|
||||
TypeUtils.getPrimaryDeclarationOfSymbol(classMemberInfo.symbol)!);
|
||||
}
|
||||
|
@ -687,7 +687,7 @@ export class TypeUtils {
|
||||
// The class derives from an unknown type, so all bets are off
|
||||
// when trying to find a member. Return an unknown symbol.
|
||||
return {
|
||||
symbol: Symbol.create(UnknownType.create(), DefaultTypeSourceId),
|
||||
symbol: Symbol.createWithType(UnknownType.create(), DefaultTypeSourceId),
|
||||
isInstanceMember: false,
|
||||
classType: UnknownType.create(),
|
||||
symbolType: UnknownType.create()
|
||||
@ -704,12 +704,13 @@ export class TypeUtils {
|
||||
return declaredType;
|
||||
}
|
||||
|
||||
return symbol.inferredType.getType();
|
||||
return symbol.getInferredType();
|
||||
}
|
||||
|
||||
static getDeclaredTypeOfSymbol(symbol: Symbol): Type | undefined {
|
||||
if (symbol.declarations) {
|
||||
const declWithDeclaredType = symbol.declarations.find(decl => decl.declaredType !== undefined);
|
||||
const declarations = symbol.getDeclarations();
|
||||
if (declarations.length > 0) {
|
||||
const declWithDeclaredType = declarations.find(decl => decl.declaredType !== undefined);
|
||||
if (declWithDeclaredType) {
|
||||
return declWithDeclaredType.declaredType;
|
||||
}
|
||||
@ -721,14 +722,14 @@ export class TypeUtils {
|
||||
// Returns the first declaration with a declared type. If no such
|
||||
// declaration exists, returns the first declaration.
|
||||
static getPrimaryDeclarationOfSymbol(symbol: Symbol): Declaration | undefined {
|
||||
if (symbol.declarations) {
|
||||
const declWithDeclaredType = symbol.declarations.find(
|
||||
decl => decl.declaredType !== undefined);
|
||||
const declarations = symbol.getDeclarations();
|
||||
if (declarations.length > 0) {
|
||||
const declWithDeclaredType = declarations.find(decl => decl.declaredType !== undefined);
|
||||
if (declWithDeclaredType) {
|
||||
return declWithDeclaredType;
|
||||
}
|
||||
|
||||
return symbol.declarations[0];
|
||||
return declarations[0];
|
||||
}
|
||||
|
||||
return undefined;
|
||||
@ -1461,33 +1462,33 @@ export class TypeUtils {
|
||||
// Validate that the type arguments match.
|
||||
const srcTypeArgs = curSrcType.getTypeArguments();
|
||||
if (srcTypeArgs) {
|
||||
assert(srcType.isSpecialBuiltIn() || srcTypeArgs.length === ancestorTypeArgs.length);
|
||||
if (srcType.isSpecialBuiltIn() || srcTypeArgs.length === ancestorTypeArgs.length) {
|
||||
for (let srcArgIndex = 0; srcArgIndex < srcTypeArgs.length; srcArgIndex++) {
|
||||
const srcTypeArg = srcTypeArgs[srcArgIndex];
|
||||
|
||||
for (let srcArgIndex = 0; srcArgIndex < srcTypeArgs.length; srcArgIndex++) {
|
||||
const srcTypeArg = srcTypeArgs[srcArgIndex];
|
||||
// In most cases, the ancestor type param count should match, but
|
||||
// there are a few special cases where this isn't true (e.g. assigning
|
||||
// a Tuple[X, Y, Z] to a tuple[W]).
|
||||
const ancestorArgIndex = srcArgIndex >= ancestorTypeParams.length ?
|
||||
ancestorTypeParams.length - 1 : srcArgIndex;
|
||||
const typeParam = ancestorTypeParams[ancestorArgIndex];
|
||||
const ancestorTypeArg = ancestorTypeArgs[ancestorArgIndex];
|
||||
|
||||
// In most cases, the ancestor type param count should match, but
|
||||
// there are a few special cases where this isn't true (e.g. assigning
|
||||
// a Tuple[X, Y, Z] to a tuple[W]).
|
||||
const ancestorArgIndex = srcArgIndex >= ancestorTypeParams.length ?
|
||||
ancestorTypeParams.length - 1 : srcArgIndex;
|
||||
const typeParam = ancestorTypeParams[ancestorArgIndex];
|
||||
const ancestorTypeArg = ancestorTypeArgs[ancestorArgIndex];
|
||||
|
||||
if (typeParam.isCovariant()) {
|
||||
if (!this.canAssignType(ancestorTypeArg, srcTypeArg,
|
||||
diag.createAddendum(), undefined, true, recursionCount + 1)) {
|
||||
return false;
|
||||
}
|
||||
} else if (typeParam.isContravariant()) {
|
||||
if (!this.canAssignType(srcTypeArg, ancestorTypeArg,
|
||||
diag.createAddendum(), undefined, true, recursionCount + 1)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!this.canAssignType(ancestorTypeArg, srcTypeArg,
|
||||
diag.createAddendum(), undefined, false, recursionCount + 1)) {
|
||||
return false;
|
||||
if (typeParam.isCovariant()) {
|
||||
if (!this.canAssignType(ancestorTypeArg, srcTypeArg,
|
||||
diag.createAddendum(), undefined, true, recursionCount + 1)) {
|
||||
return false;
|
||||
}
|
||||
} else if (typeParam.isContravariant()) {
|
||||
if (!this.canAssignType(srcTypeArg, ancestorTypeArg,
|
||||
diag.createAddendum(), undefined, true, recursionCount + 1)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!this.canAssignType(ancestorTypeArg, srcTypeArg,
|
||||
diag.createAddendum(), undefined, false, recursionCount + 1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ export enum TypeCategory {
|
||||
|
||||
export type LiteralValue = number | boolean | string;
|
||||
|
||||
const MaxRecursionCount = 20;
|
||||
const MaxRecursionCount = 16;
|
||||
|
||||
export type InheritanceChain = (ClassType | UnknownType)[];
|
||||
|
||||
@ -685,8 +685,8 @@ export class FunctionType extends Type {
|
||||
this._functionDetails = {
|
||||
flags,
|
||||
parameters: [],
|
||||
inferredReturnType: new InferredType(UnknownType.create()),
|
||||
inferredYieldType: new InferredType(UnknownType.create())
|
||||
inferredReturnType: new InferredType(),
|
||||
inferredYieldType: new InferredType()
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user