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:
Eric Traut 2019-05-04 16:33:38 -07:00
parent f121957579
commit e8286aa894
9 changed files with 324 additions and 303 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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)) {

View File

@ -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;
}

View File

@ -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());
}
}

View File

@ -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.

View File

@ -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)!);
}

View File

@ -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;
}
}
}
}

View File

@ -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()
};
}