mirror of
https://github.com/microsoft/pyright.git
synced 2024-10-05 12:27:30 +03:00
Fixed a few bugs in type analyzer.
This commit is contained in:
parent
cbaaa0ff84
commit
00ae7f1400
@ -601,7 +601,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
if (declaredReturnType) {
|
||||
if (!TypeUtils.canAssignType(declaredReturnType, returnType)) {
|
||||
this._addError(
|
||||
`Expression of type '${ returnType.asString() }' cannot not assigned ` +
|
||||
`Expression of type '${ returnType.asString() }' cannot be assigned ` +
|
||||
`to return type '${ declaredReturnType.asString() }'`,
|
||||
node.returnExpression ? node.returnExpression : node);
|
||||
}
|
||||
@ -974,10 +974,11 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
ClassTypeFlags.BuiltInClass | ClassTypeFlags.SpecialBuiltIn,
|
||||
AnalyzerNodeInfo.getTypeSourceId(node));
|
||||
|
||||
let baseClass = TypeAnnotation.getBuiltInType(this._currentScope,
|
||||
let aliasClass = TypeAnnotation.getBuiltInType(this._currentScope,
|
||||
assignedName.toLowerCase());
|
||||
if (baseClass instanceof ClassType) {
|
||||
specialClassType.addBaseClass(baseClass, false);
|
||||
if (aliasClass instanceof ClassType) {
|
||||
specialClassType.addBaseClass(aliasClass, false);
|
||||
specialClassType.setAliasClass(aliasClass);
|
||||
}
|
||||
|
||||
specialType = specialClassType;
|
||||
@ -1453,7 +1454,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
// The stdlib collections.pyi stub file defines namedtuple as a function
|
||||
// rather than a class, so we need to check for it here.
|
||||
if (callType.getSpecialBuiltInName() === 'namedtuple') {
|
||||
exprType = TypeAnnotation.getNamedTupleType(node, false,
|
||||
exprType = TypeAnnotation.createNamedTupleType(node, false,
|
||||
this._currentScope, this._fileInfo.diagnosticSink);
|
||||
} else {
|
||||
exprType = callType.getEffectiveReturnType();
|
||||
@ -1488,7 +1489,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
this._currentScope, this._getConditionalDiagnosticSink());
|
||||
} else if (className === 'NamedTuple') {
|
||||
// Handle the NamedTuple case specially because it's a class factory.
|
||||
exprType = TypeAnnotation.getNamedTupleType(node, true,
|
||||
exprType = TypeAnnotation.createNamedTupleType(node, true,
|
||||
this._currentScope, this._getConditionalDiagnosticSink());
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import { Scope, ScopeType } from './scope';
|
||||
import { Symbol } from './symbol';
|
||||
import { AnyType, ClassType, ClassTypeFlags, FunctionParameter, FunctionType,
|
||||
FunctionTypeFlags, ModuleType, NoneType, ObjectType, OverloadedFunctionType,
|
||||
PropertyType, TupleType, Type, TypeVarType, UnknownType } from './types';
|
||||
PropertyType, TupleType, Type, TypeVarType, UnionType, UnknownType } from './types';
|
||||
import { TypeUtils } from './typeUtils';
|
||||
|
||||
interface TypeResult {
|
||||
@ -116,7 +116,7 @@ export class TypeAnnotation {
|
||||
|
||||
// Creates a new custom tuple factory class with named values.
|
||||
// Supports both typed and untyped variants.
|
||||
static getNamedTupleType(node: CallExpressionNode, includesTypes: boolean,
|
||||
static createNamedTupleType(node: CallExpressionNode, includesTypes: boolean,
|
||||
currentScope: Scope, diagSink: TextRangeDiagnosticSink): ClassType {
|
||||
let className = 'namedtuple';
|
||||
if (node.arguments.length === 0) {
|
||||
@ -134,6 +134,7 @@ export class TypeAnnotation {
|
||||
|
||||
let classType = new ClassType(className, ClassTypeFlags.None,
|
||||
AnalyzerNodeInfo.getTypeSourceId(node));
|
||||
classType.addBaseClass(this.getBuiltInType(currentScope, 'NamedTuple'), false);
|
||||
const classFields = classType.getClassFields();
|
||||
classFields.set('__class__', new Symbol(classType, DefaultTypeSourceId));
|
||||
const instanceFields = classType.getInstanceFields();
|
||||
@ -624,6 +625,10 @@ export class TypeAnnotation {
|
||||
if (baseTypeResult.type instanceof ClassType) {
|
||||
[type, isClassType] = this.specializeClassType(baseTypeResult.type,
|
||||
node.indexExpression, currentScope, diagSink);
|
||||
} else if (baseTypeResult.type instanceof UnionType) {
|
||||
// TODO - need to implement
|
||||
} else if (baseTypeResult.type instanceof FunctionType) {
|
||||
// TODO - need to implement
|
||||
} else if (!baseTypeResult.type.isAny()) {
|
||||
diagSink.addErrorWithTextRange(
|
||||
`'Unsupported type expression: indexed other (${ baseTypeResult.type.asString() })`,
|
||||
@ -690,7 +695,7 @@ export class TypeAnnotation {
|
||||
if (className === 'TypeVar') {
|
||||
type = this.getTypeVarType(node, currentScope, diagSink);
|
||||
} else if (className === 'NamedTuple') {
|
||||
type = this.getNamedTupleType(node, true, currentScope, diagSink);
|
||||
type = this.createNamedTupleType(node, true, currentScope, diagSink);
|
||||
isClassType = true;
|
||||
} else {
|
||||
type = UnknownType.create();
|
||||
@ -700,7 +705,7 @@ export class TypeAnnotation {
|
||||
// The stdlib collections/__init__.pyi stub file defines namedtuple
|
||||
// as a function rather than a class, so we need to check for it here.
|
||||
if (baseTypeResult.type.getSpecialBuiltInName() === 'namedtuple') {
|
||||
type = this.getNamedTupleType(node, false, currentScope, diagSink);
|
||||
type = this.createNamedTupleType(node, false, currentScope, diagSink);
|
||||
isClassType = true;
|
||||
} else {
|
||||
type = baseTypeResult.type.getEffectiveReturnType();
|
||||
|
@ -207,6 +207,7 @@ export class TypeUtils {
|
||||
}
|
||||
|
||||
if (srcType.isDerivedFrom(destType)) {
|
||||
// TODO - need to validate type parameter matches
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -230,7 +231,9 @@ export class TypeUtils {
|
||||
// Looks up a member in a class using the multiple-inheritance rules
|
||||
// defined by Python. For more detials, see this note on method resolution
|
||||
// order: https://www.python.org/download/releases/2.3/mro/.
|
||||
static lookUpClassMember(classType: Type, memberName: string, includeInstanceFields = true): ClassMember | undefined {
|
||||
static lookUpClassMember(classType: Type, memberName: string,
|
||||
includeInstanceFields = true): ClassMember | undefined {
|
||||
|
||||
if (classType instanceof ClassType) {
|
||||
// TODO - for now, use naive depth-first search.
|
||||
|
||||
|
@ -193,6 +193,7 @@ interface ClassDetails {
|
||||
flags: ClassTypeFlags;
|
||||
typeSourceId: TypeSourceId;
|
||||
baseClasses: BaseClass[];
|
||||
aliasClass?: ClassType;
|
||||
classFields: SymbolTable;
|
||||
instanceFields: SymbolTable;
|
||||
typeParameters: TypeVarType[];
|
||||
@ -269,6 +270,10 @@ export class ClassType extends Type {
|
||||
return this._classDetails.baseClasses;
|
||||
}
|
||||
|
||||
setAliasClass(type: ClassType) {
|
||||
this._classDetails.aliasClass = type;
|
||||
}
|
||||
|
||||
addBaseClass(type: Type, isMetaclass: boolean) {
|
||||
this._classDetails.baseClasses.push({ isMetaclass, type });
|
||||
}
|
||||
@ -421,7 +426,14 @@ export class ClassType extends Type {
|
||||
// Determines whether this is a subclass (derived class)
|
||||
// of the specified class.
|
||||
isDerivedFrom(type2: ClassType): boolean {
|
||||
if (type2 === this) {
|
||||
if (this._classDetails === type2._classDetails) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Is one class type an alias of the other? This is used for some
|
||||
// built-in types (e.g. Tuple and tuple).
|
||||
if (this._classDetails.aliasClass === type2 ||
|
||||
type2._classDetails.aliasClass === this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user