Simplified interface to "assignTypeToXXX" methods.

This commit is contained in:
Eric Traut 2024-06-07 14:02:05 -07:00
parent 4b84651950
commit a0af8c5c8c
4 changed files with 97 additions and 115 deletions

View File

@ -941,12 +941,7 @@ export function getTypeOfAugmentedAssignment(
typeResult = { type, isIncomplete }; typeResult = { type, isIncomplete };
} }
evaluator.assignTypeToExpression( evaluator.assignTypeToExpression(node.destExpression, typeResult, node.rightExpression);
node.destExpression,
typeResult.type,
!!typeResult.isIncomplete,
node.rightExpression
);
return typeResult; return typeResult;
} }

View File

@ -1577,7 +1577,11 @@ export function assignTypeToPatternTargets(
case ParseNodeType.PatternAs: { case ParseNodeType.PatternAs: {
if (pattern.target) { if (pattern.target) {
evaluator.assignTypeToExpression(pattern.target, narrowedType, isTypeIncomplete, pattern.target); evaluator.assignTypeToExpression(
pattern.target,
{ type: narrowedType, isIncomplete: isTypeIncomplete },
pattern.target
);
} }
let runningNarrowedType = narrowedType; let runningNarrowedType = narrowedType;
@ -1621,7 +1625,11 @@ export function assignTypeToPatternTargets(
} }
} }
} else { } else {
evaluator.assignTypeToExpression(pattern.target, narrowedType, isTypeIncomplete, pattern.target); evaluator.assignTypeToExpression(
pattern.target,
{ type: narrowedType, isIncomplete: isTypeIncomplete },
pattern.target
);
} }
break; break;
} }
@ -1709,8 +1717,7 @@ export function assignTypeToPatternTargets(
: UnknownType.create(); : UnknownType.create();
evaluator.assignTypeToExpression( evaluator.assignTypeToExpression(
mappingEntry.target, mappingEntry.target,
dictType, { type: dictType, isIncomplete: isTypeIncomplete },
isTypeIncomplete,
mappingEntry.target mappingEntry.target
); );
} }

View File

@ -1255,8 +1255,7 @@ export function createTypeEvaluator(
typeResult = getTypeOfExpression(node.rightExpression, flags, inferenceContext, signatureTracker); typeResult = getTypeOfExpression(node.rightExpression, flags, inferenceContext, signatureTracker);
assignTypeToExpression( assignTypeToExpression(
node.leftExpression, node.leftExpression,
typeResult.type, typeResult,
!!typeResult.isIncomplete,
node.rightExpression, node.rightExpression,
/* ignoreEmptyContainers */ true, /* ignoreEmptyContainers */ true,
/* allowAssignmentToFinalVar */ true /* allowAssignmentToFinalVar */ true
@ -1270,13 +1269,7 @@ export function createTypeEvaluator(
} }
typeResult = getTypeOfExpression(node.rightExpression, flags, inferenceContext, signatureTracker); typeResult = getTypeOfExpression(node.rightExpression, flags, inferenceContext, signatureTracker);
assignTypeToExpression( assignTypeToExpression(node.name, typeResult, node.rightExpression, /* ignoreEmptyContainers */ true);
node.name,
typeResult.type,
!!typeResult.isIncomplete,
node.rightExpression,
/* ignoreEmptyContainers */ true
);
break; break;
} }
@ -3271,8 +3264,7 @@ export function createTypeEvaluator(
function assignTypeToNameNode( function assignTypeToNameNode(
nameNode: NameNode, nameNode: NameNode,
type: Type, typeResult: TypeResult,
isTypeIncomplete: boolean,
ignoreEmptyContainers: boolean, ignoreEmptyContainers: boolean,
srcExpression?: ParseNode, srcExpression?: ParseNode,
allowAssignmentToFinalVar = false, allowAssignmentToFinalVar = false,
@ -3311,24 +3303,24 @@ export function createTypeEvaluator(
} }
// We found an existing declared type. Make sure the type is assignable. // We found an existing declared type. Make sure the type is assignable.
let destType = type; let destType = typeResult.type;
const isTypeAlias = const isTypeAlias =
!!declaredType && isClassInstance(declaredType) && ClassType.isBuiltIn(declaredType, 'TypeAlias'); !!declaredType && isClassInstance(declaredType) && ClassType.isBuiltIn(declaredType, 'TypeAlias');
if (declaredType && !isTypeAlias) { if (declaredType && !isTypeAlias) {
let diagAddendum = new DiagnosticAddendum(); let diagAddendum = new DiagnosticAddendum();
if (!assignType(declaredType, type, diagAddendum)) { if (!assignType(declaredType, typeResult.type, diagAddendum)) {
// If there was an expected type mismatch, use that diagnostic // If there was an expected type mismatch, use that diagnostic
// addendum because it will be more informative. // addendum because it will be more informative.
if (expectedTypeDiagAddendum) { if (expectedTypeDiagAddendum) {
diagAddendum = expectedTypeDiagAddendum; diagAddendum = expectedTypeDiagAddendum;
} }
if (!isTypeIncomplete) { if (!typeResult.isIncomplete) {
addDiagnostic( addDiagnostic(
DiagnosticRule.reportAssignmentType, DiagnosticRule.reportAssignmentType,
LocMessage.typeAssignmentMismatch().format(printSrcDestTypes(type, declaredType)) + LocMessage.typeAssignmentMismatch().format(printSrcDestTypes(typeResult.type, declaredType)) +
diagAddendum.getString(), diagAddendum.getString(),
srcExpression ?? nameNode, srcExpression ?? nameNode,
diagAddendum.getEffectiveTextRange() ?? srcExpression ?? nameNode diagAddendum.getEffectiveTextRange() ?? srcExpression ?? nameNode
@ -3339,7 +3331,7 @@ export function createTypeEvaluator(
destType = declaredType; destType = declaredType;
} else { } else {
// Constrain the resulting type to match the declared type. // Constrain the resulting type to match the declared type.
destType = narrowTypeBasedOnAssignment(nameNode, declaredType, type); destType = narrowTypeBasedOnAssignment(nameNode, declaredType, typeResult).type;
} }
} else { } else {
// If this is a member name (within a class scope) and the member name // If this is a member name (within a class scope) and the member name
@ -3386,7 +3378,7 @@ export function createTypeEvaluator(
} }
} }
if (!isTypeIncomplete) { if (!typeResult.isIncomplete) {
reportPossibleUnknownAssignment( reportPossibleUnknownAssignment(
fileInfo.diagnosticRuleSet.reportUnknownVariableType, fileInfo.diagnosticRuleSet.reportUnknownVariableType,
DiagnosticRule.reportUnknownVariableType, DiagnosticRule.reportUnknownVariableType,
@ -3397,13 +3389,12 @@ export function createTypeEvaluator(
); );
} }
writeTypeCache(nameNode, { type: destType, isIncomplete: isTypeIncomplete }, EvaluatorFlags.None); writeTypeCache(nameNode, { type: destType, isIncomplete: typeResult.isIncomplete }, EvaluatorFlags.None);
} }
function assignTypeToMemberAccessNode( function assignTypeToMemberAccessNode(
target: MemberAccessNode, target: MemberAccessNode,
type: Type, typeResult: TypeResult,
isTypeIncomplete: boolean,
srcExpr?: ExpressionNode, srcExpr?: ExpressionNode,
expectedTypeDiagAddendum?: DiagnosticAddendum expectedTypeDiagAddendum?: DiagnosticAddendum
) { ) {
@ -3421,23 +3412,11 @@ export function createTypeEvaluator(
if (classTypeResults && isInstantiableClass(classTypeResults.classType)) { if (classTypeResults && isInstantiableClass(classTypeResults.classType)) {
if (isClassInstance(baseType)) { if (isClassInstance(baseType)) {
if (ClassType.isSameGenericClass(baseType, classTypeResults.classType)) { if (ClassType.isSameGenericClass(baseType, classTypeResults.classType)) {
assignTypeToMemberVariable( assignTypeToMemberVariable(target, typeResult, /* isInstanceMember */ true, srcExpr);
target,
type,
isTypeIncomplete,
/* isInstanceMember */ true,
srcExpr
);
} }
} else if (isInstantiableClass(baseType)) { } else if (isInstantiableClass(baseType)) {
if (ClassType.isSameGenericClass(baseType, classTypeResults.classType)) { if (ClassType.isSameGenericClass(baseType, classTypeResults.classType)) {
assignTypeToMemberVariable( assignTypeToMemberVariable(target, typeResult, /* isInstanceMember */ false, srcExpr);
target,
type,
isTypeIncomplete,
/* isInstanceMember */ false,
srcExpr
);
} }
} }
@ -3465,7 +3444,7 @@ export function createTypeEvaluator(
baseTypeResult, baseTypeResult,
{ {
method: 'set', method: 'set',
setType: { type, isIncomplete: isTypeIncomplete }, setType: typeResult,
setErrorNode: srcExpr, setErrorNode: srcExpr,
setExpectedTypeDiag: expectedTypeDiagAddendum, setExpectedTypeDiag: expectedTypeDiagAddendum,
}, },
@ -3477,8 +3456,8 @@ export function createTypeEvaluator(
} }
const resultToCache: TypeResult = { const resultToCache: TypeResult = {
type: setTypeResult.narrowedTypeForSet ?? type, type: setTypeResult.narrowedTypeForSet ?? typeResult.type,
isIncomplete: isTypeIncomplete, isIncomplete: typeResult.isIncomplete,
memberAccessDeprecationInfo: setTypeResult.memberAccessDeprecationInfo, memberAccessDeprecationInfo: setTypeResult.memberAccessDeprecationInfo,
}; };
writeTypeCache(target.memberName, resultToCache, EvaluatorFlags.None); writeTypeCache(target.memberName, resultToCache, EvaluatorFlags.None);
@ -3487,8 +3466,7 @@ export function createTypeEvaluator(
function assignTypeToMemberVariable( function assignTypeToMemberVariable(
node: MemberAccessNode, node: MemberAccessNode,
srcType: Type, typeResult: TypeResult,
isTypeIncomplete: boolean,
isInstanceMember: boolean, isInstanceMember: boolean,
srcExprNode?: ExpressionNode srcExprNode?: ExpressionNode
) { ) {
@ -3591,7 +3569,7 @@ export function createTypeEvaluator(
// The class variable is accessed in this case. // The class variable is accessed in this case.
setSymbolAccessed(fileInfo, memberInfo.symbol, node.memberName); setSymbolAccessed(fileInfo, memberInfo.symbol, node.memberName);
const memberType = getTypeOfMember(memberInfo); const memberType = getTypeOfMember(memberInfo);
srcType = combineTypes([srcType, memberType]); typeResult = { ...typeResult, type: combineTypes([typeResult.type, memberType]) };
} }
} }
} }
@ -3600,12 +3578,12 @@ export function createTypeEvaluator(
// Look up the member info again, now that we've potentially updated it. // Look up the member info again, now that we've potentially updated it.
memberInfo = lookUpClassMember(classTypeInfo.classType, memberName, MemberAccessFlags.DeclaredTypesOnly); memberInfo = lookUpClassMember(classTypeInfo.classType, memberName, MemberAccessFlags.DeclaredTypesOnly);
if (!memberInfo && srcExprNode && !isTypeIncomplete) { if (!memberInfo && srcExprNode && !typeResult.isIncomplete) {
reportPossibleUnknownAssignment( reportPossibleUnknownAssignment(
fileInfo.diagnosticRuleSet.reportUnknownMemberType, fileInfo.diagnosticRuleSet.reportUnknownMemberType,
DiagnosticRule.reportUnknownMemberType, DiagnosticRule.reportUnknownMemberType,
node.memberName, node.memberName,
srcType, typeResult.type,
node, node,
/* ignoreEmptyContainers */ true /* ignoreEmptyContainers */ true
); );
@ -3615,8 +3593,7 @@ export function createTypeEvaluator(
function assignTypeToTupleOrListNode( function assignTypeToTupleOrListNode(
target: TupleNode | ListNode, target: TupleNode | ListNode,
type: Type, typeResult: TypeResult,
isTypeIncomplete: boolean,
srcExpr: ExpressionNode srcExpr: ExpressionNode
) { ) {
const targetExpressions = target.nodeType === ParseNodeType.List ? target.entries : target.expressions; const targetExpressions = target.nodeType === ParseNodeType.List ? target.entries : target.expressions;
@ -3632,11 +3609,11 @@ export function createTypeEvaluator(
// entries at that location. // entries at that location.
const unpackIndex = targetExpressions.findIndex((expr) => expr.nodeType === ParseNodeType.Unpack); const unpackIndex = targetExpressions.findIndex((expr) => expr.nodeType === ParseNodeType.Unpack);
type = makeTopLevelTypeVarsConcrete(type); typeResult = { ...typeResult, type: makeTopLevelTypeVarsConcrete(typeResult.type) };
const diagAddendum = new DiagnosticAddendum(); const diagAddendum = new DiagnosticAddendum();
doForEachSubtype(type, (subtype) => { doForEachSubtype(typeResult.type, (subtype) => {
// Is this subtype a tuple? // Is this subtype a tuple?
const tupleType = getSpecializedTupleType(subtype); const tupleType = getSpecializedTupleType(subtype);
if (tupleType && tupleType.tupleTypeArguments) { if (tupleType && tupleType.tupleTypeArguments) {
@ -3708,8 +3685,11 @@ export function createTypeEvaluator(
// The assigned expression isn't a tuple, so it had better // The assigned expression isn't a tuple, so it had better
// be some iterable type. // be some iterable type.
const iterableType = const iterableType =
getTypeOfIterator({ type: subtype, isIncomplete: isTypeIncomplete }, /* isAsync */ false, srcExpr) getTypeOfIterator(
?.type ?? UnknownType.create(); { type: subtype, isIncomplete: typeResult.isIncomplete },
/* isAsync */ false,
srcExpr
)?.type ?? UnknownType.create();
for (let index = 0; index < targetExpressions.length; index++) { for (let index = 0; index < targetExpressions.length; index++) {
targetTypes[index].push(addConditionToType(iterableType, getTypeCondition(subtype))); targetTypes[index].push(addConditionToType(iterableType, getTypeCondition(subtype)));
} }
@ -3723,7 +3703,7 @@ export function createTypeEvaluator(
? LocMessage.listAssignmentMismatch() ? LocMessage.listAssignmentMismatch()
: LocMessage.tupleAssignmentMismatch() : LocMessage.tupleAssignmentMismatch()
).format({ ).format({
type: printType(type), type: printType(typeResult.type),
}) + diagAddendum.getString(), }) + diagAddendum.getString(),
target target
); );
@ -3735,10 +3715,15 @@ export function createTypeEvaluator(
const typeList = targetTypes[index]; const typeList = targetTypes[index];
const targetType = typeList.length === 0 ? UnknownType.create() : combineTypes(typeList); const targetType = typeList.length === 0 ? UnknownType.create() : combineTypes(typeList);
assignTypeToExpression(expr, targetType, isTypeIncomplete, srcExpr, /* ignoreEmptyContainers */ true); assignTypeToExpression(
expr,
{ type: targetType, isIncomplete: typeResult.isIncomplete },
srcExpr,
/* ignoreEmptyContainers */ true
);
}); });
writeTypeCache(target, { type, isIncomplete: isTypeIncomplete }, EvaluatorFlags.None); writeTypeCache(target, typeResult, EvaluatorFlags.None);
} }
// If the type includes promotion types, expand these to their constituent types. // If the type includes promotion types, expand these to their constituent types.
@ -4056,15 +4041,14 @@ export function createTypeEvaluator(
function assignTypeToExpression( function assignTypeToExpression(
target: ExpressionNode, target: ExpressionNode,
type: Type, typeResult: TypeResult,
isTypeIncomplete: boolean,
srcExpr: ExpressionNode, srcExpr: ExpressionNode,
ignoreEmptyContainers = false, ignoreEmptyContainers = false,
allowAssignmentToFinalVar = false, allowAssignmentToFinalVar = false,
expectedTypeDiagAddendum?: DiagnosticAddendum expectedTypeDiagAddendum?: DiagnosticAddendum
) { ) {
// Is the source expression a TypeVar() call? // Is the source expression a TypeVar() call?
if (isTypeVar(type)) { if (isTypeVar(typeResult.type)) {
if (srcExpr && srcExpr.nodeType === ParseNodeType.Call) { if (srcExpr && srcExpr.nodeType === ParseNodeType.Call) {
const callType = getTypeOfExpression(srcExpr.leftExpression, EvaluatorFlags.CallBaseDefaults).type; const callType = getTypeOfExpression(srcExpr.leftExpression, EvaluatorFlags.CallBaseDefaults).type;
if ( if (
@ -4075,14 +4059,17 @@ export function createTypeEvaluator(
) { ) {
const typeVarTarget = const typeVarTarget =
target.nodeType === ParseNodeType.TypeAnnotation ? target.valueExpression : target; target.nodeType === ParseNodeType.TypeAnnotation ? target.valueExpression : target;
if (typeVarTarget.nodeType !== ParseNodeType.Name || typeVarTarget.value !== type.details.name) { if (
typeVarTarget.nodeType !== ParseNodeType.Name ||
typeVarTarget.value !== typeResult.type.details.name
) {
addError( addError(
type.details.isParamSpec typeResult.type.details.isParamSpec
? LocMessage.paramSpecAssignedName().format({ ? LocMessage.paramSpecAssignedName().format({
name: TypeVarType.getReadableName(type), name: TypeVarType.getReadableName(typeResult.type),
}) })
: LocMessage.typeVarAssignedName().format({ : LocMessage.typeVarAssignedName().format({
name: TypeVarType.getReadableName(type), name: TypeVarType.getReadableName(typeResult.type),
}), }),
typeVarTarget typeVarTarget
); );
@ -4094,14 +4081,15 @@ export function createTypeEvaluator(
// If the type was partially unbound, an error will have already been logged. // If the type was partially unbound, an error will have already been logged.
// Remove the unbound before assigning to the target expression so the unbound // Remove the unbound before assigning to the target expression so the unbound
// error doesn't propagate. // error doesn't propagate.
type = removeUnbound(type); if (findSubtype(typeResult.type, (subtype) => isUnbound(subtype))) {
typeResult = { ...typeResult, type: removeUnbound(typeResult.type) };
}
switch (target.nodeType) { switch (target.nodeType) {
case ParseNodeType.Name: { case ParseNodeType.Name: {
assignTypeToNameNode( assignTypeToNameNode(
target, target,
type, typeResult,
isTypeIncomplete,
ignoreEmptyContainers, ignoreEmptyContainers,
srcExpr, srcExpr,
allowAssignmentToFinalVar, allowAssignmentToFinalVar,
@ -4111,7 +4099,7 @@ export function createTypeEvaluator(
} }
case ParseNodeType.MemberAccess: { case ParseNodeType.MemberAccess: {
assignTypeToMemberAccessNode(target, type, isTypeIncomplete, srcExpr, expectedTypeDiagAddendum); assignTypeToMemberAccessNode(target, typeResult, srcExpr, expectedTypeDiagAddendum);
break; break;
} }
@ -4123,20 +4111,20 @@ export function createTypeEvaluator(
baseTypeResult, baseTypeResult,
{ {
method: 'set', method: 'set',
setType: { type, isIncomplete: isTypeIncomplete }, setType: typeResult,
setErrorNode: srcExpr, setErrorNode: srcExpr,
setExpectedTypeDiag: expectedTypeDiagAddendum, setExpectedTypeDiag: expectedTypeDiagAddendum,
}, },
EvaluatorFlags.None EvaluatorFlags.None
); );
writeTypeCache(target, { type, isIncomplete: isTypeIncomplete }, EvaluatorFlags.None); writeTypeCache(target, typeResult, EvaluatorFlags.None);
break; break;
} }
case ParseNodeType.List: case ParseNodeType.List:
case ParseNodeType.Tuple: { case ParseNodeType.Tuple: {
assignTypeToTupleOrListNode(target, type, isTypeIncomplete, srcExpr); assignTypeToTupleOrListNode(target, typeResult, srcExpr);
break; break;
} }
@ -4157,12 +4145,12 @@ export function createTypeEvaluator(
isClassInstance(annotationType) && ClassType.isBuiltIn(annotationType, 'TypeAlias'); isClassInstance(annotationType) && ClassType.isBuiltIn(annotationType, 'TypeAlias');
if (!isTypeAliasAnnotation) { if (!isTypeAliasAnnotation) {
if (assignType(annotationType, type)) { if (assignType(annotationType, typeResult.type)) {
// Don't attempt to narrow based on the annotated type if the type // Don't attempt to narrow based on the annotated type if the type
// is a enum because the annotated type in an enum doesn't reflect // is a enum because the annotated type in an enum doesn't reflect
// the type of the symbol. // the type of the symbol.
if (!isClassInstance(type) || !ClassType.isEnumClass(type)) { if (!isClassInstance(typeResult.type) || !ClassType.isEnumClass(typeResult.type)) {
type = narrowTypeBasedOnAssignment(target, annotationType, type); typeResult = narrowTypeBasedOnAssignment(target, annotationType, typeResult);
} }
} }
} }
@ -4170,8 +4158,7 @@ export function createTypeEvaluator(
assignTypeToExpression( assignTypeToExpression(
target.valueExpression, target.valueExpression,
type, typeResult,
isTypeIncomplete,
srcExpr, srcExpr,
ignoreEmptyContainers, ignoreEmptyContainers,
allowAssignmentToFinalVar, allowAssignmentToFinalVar,
@ -4184,8 +4171,10 @@ export function createTypeEvaluator(
if (target.expression.nodeType === ParseNodeType.Name) { if (target.expression.nodeType === ParseNodeType.Name) {
assignTypeToNameNode( assignTypeToNameNode(
target.expression, target.expression,
getBuiltInObject(target.expression, 'list', [type]), {
/* isIncomplete */ false, type: getBuiltInObject(target.expression, 'list', [typeResult.type]),
isIncomplete: typeResult.isIncomplete,
},
ignoreEmptyContainers, ignoreEmptyContainers,
srcExpr srcExpr
); );
@ -5889,7 +5878,7 @@ export function createTypeEvaluator(
// descriptor-based accesses. // descriptor-based accesses.
narrowedTypeForSet = isDescriptorApplied narrowedTypeForSet = isDescriptorApplied
? usage.setType.type ? usage.setType.type
: narrowTypeBasedOnAssignment(errorNode, type, usage.setType.type); : narrowTypeBasedOnAssignment(errorNode, type, usage.setType).type;
} }
// Verify that the assigned type is compatible. // Verify that the assigned type is compatible.
@ -14622,12 +14611,7 @@ export function createTypeEvaluator(
) ?? { type: UnknownType.create(), isIncomplete: iterableTypeResult.isIncomplete }; ) ?? { type: UnknownType.create(), isIncomplete: iterableTypeResult.isIncomplete };
const targetExpr = node.targetExpression; const targetExpr = node.targetExpression;
assignTypeToExpression( assignTypeToExpression(targetExpr, itemTypeResult, node.iterableExpression);
targetExpr,
itemTypeResult.type,
!!itemTypeResult.isIncomplete,
node.iterableExpression
);
} else { } else {
assert(node.nodeType === ParseNodeType.ComprehensionIf); assert(node.nodeType === ParseNodeType.ComprehensionIf);
@ -16286,8 +16270,7 @@ export function createTypeEvaluator(
assignTypeToExpression( assignTypeToExpression(
node.leftExpression, node.leftExpression,
rightHandType, { type: rightHandType, isIncomplete },
isIncomplete,
node.rightExpression, node.rightExpression,
/* ignoreEmptyContainers */ true, /* ignoreEmptyContainers */ true,
/* allowAssignmentToFinalVar */ true, /* allowAssignmentToFinalVar */ true,
@ -18814,8 +18797,7 @@ export function createTypeEvaluator(
assignTypeToExpression( assignTypeToExpression(
node.targetExpression, node.targetExpression,
iteratedType, { type: iteratedType, isIncomplete: iteratorTypeResult.isIncomplete },
!!iteratorTypeResult.isIncomplete,
node.targetExpression node.targetExpression
); );
@ -18888,7 +18870,7 @@ export function createTypeEvaluator(
} }
if (node.name) { if (node.name) {
assignTypeToExpression(node.name, targetType, /* isIncomplete */ false, node.name); assignTypeToExpression(node.name, { type: targetType }, node.name);
} }
writeTypeCache(node, { type: targetType }, EvaluatorFlags.None); writeTypeCache(node, { type: targetType }, EvaluatorFlags.None);
@ -18994,7 +18976,11 @@ export function createTypeEvaluator(
}); });
if (node.target) { if (node.target) {
assignTypeToExpression(node.target, scopedType, !!exprTypeResult.isIncomplete, node.target); assignTypeToExpression(
node.target,
{ type: scopedType, isIncomplete: exprTypeResult.isIncomplete },
node.target
);
} }
writeTypeCache(node, { type: scopedType, isIncomplete: !!exprTypeResult.isIncomplete }, EvaluatorFlags.None); writeTypeCache(node, { type: scopedType, isIncomplete: !!exprTypeResult.isIncomplete }, EvaluatorFlags.None);
@ -19032,7 +19018,7 @@ export function createTypeEvaluator(
} }
} }
assignTypeToNameNode(symbolNameNode, symbolType, /* isIncomplete */ false, /* ignoreEmptyContainers */ false); assignTypeToNameNode(symbolNameNode, { type: symbolType }, /* ignoreEmptyContainers */ false);
writeTypeCache(node, { type: symbolType }, EvaluatorFlags.None); writeTypeCache(node, { type: symbolType }, EvaluatorFlags.None);
} }
@ -19115,7 +19101,7 @@ export function createTypeEvaluator(
} }
} }
assignTypeToNameNode(aliasNode, symbolType, /* isIncomplete */ false, /* ignoreEmptyContainers */ false); assignTypeToNameNode(aliasNode, { type: symbolType }, /* ignoreEmptyContainers */ false);
writeTypeCache(node, { type: symbolType }, EvaluatorFlags.None); writeTypeCache(node, { type: symbolType }, EvaluatorFlags.None);
} }
@ -19259,12 +19245,7 @@ export function createTypeEvaluator(
} }
} }
assignTypeToNameNode( assignTypeToNameNode(symbolNameNode, { type: symbolType }, /* ignoreEmptyContainers */ false);
symbolNameNode,
symbolType,
/* isIncomplete */ false,
/* ignoreEmptyContainers */ false
);
writeTypeCache(node, { type: symbolType }, EvaluatorFlags.None); writeTypeCache(node, { type: symbolType }, EvaluatorFlags.None);
} }
@ -26043,14 +26024,18 @@ export function createTypeEvaluator(
// When a value is assigned to a variable with a declared type, // When a value is assigned to a variable with a declared type,
// we may be able to narrow the type based on the assignment. // we may be able to narrow the type based on the assignment.
function narrowTypeBasedOnAssignment(node: ExpressionNode, declaredType: Type, assignedType: Type): Type { function narrowTypeBasedOnAssignment(
// TODO: The rules for narrowing types on assignment are defined in node: ExpressionNode,
declaredType: Type,
assignedTypeResult: TypeResult
): TypeResult {
// TODO: The rules for narrowing types on assignment are not defined in
// the typing spec. Pyright's current logic is currently not even internally // the typing spec. Pyright's current logic is currently not even internally
// consistent and probably not sound from a type theory perspective. It // consistent and probably not sound from a type theory perspective. It
// should be completely reworked once there has been a public discussion // should be completely reworked once there has been a public discussion
// about the correct behavior. // about the correct behavior.
const narrowedType = mapSubtypes(assignedType, (assignedSubtype) => { const narrowedType = mapSubtypes(assignedTypeResult.type, (assignedSubtype) => {
// Handle the special case where the assigned type is a literal type. // Handle the special case where the assigned type is a literal type.
// Some types include very large unions of literal types, and we don't // Some types include very large unions of literal types, and we don't
// want to use an n^2 loop to compare them. // want to use an n^2 loop to compare them.
@ -26127,12 +26112,12 @@ export function createTypeEvaluator(
// with the declared type. In strict mode, this will retain the "unknown type" // with the declared type. In strict mode, this will retain the "unknown type"
// diagnostics while still providing reasonable completion suggestions. // diagnostics while still providing reasonable completion suggestions.
if (isIncompleteUnknown(narrowedType)) { if (isIncompleteUnknown(narrowedType)) {
return narrowedType; return { type: narrowedType };
} else if (isUnknown(narrowedType)) { } else if (isUnknown(narrowedType)) {
return combineTypes([narrowedType, declaredType]); return { type: combineTypes([narrowedType, declaredType]) };
} }
return narrowedType; return { type: narrowedType };
} }
function validateOverrideMethod( function validateOverrideMethod(

View File

@ -631,12 +631,7 @@ export interface TypeEvaluator {
signatureTracker: UniqueSignatureTracker | undefined signatureTracker: UniqueSignatureTracker | undefined
) => CallResult; ) => CallResult;
validateTypeArg: (argResult: TypeResultWithNode, options?: ValidateTypeArgsOptions) => boolean; validateTypeArg: (argResult: TypeResultWithNode, options?: ValidateTypeArgsOptions) => boolean;
assignTypeToExpression: ( assignTypeToExpression: (target: ExpressionNode, typeResult: TypeResult, srcExpr: ExpressionNode) => void;
target: ExpressionNode,
type: Type,
isTypeIncomplete: boolean,
srcExpr: ExpressionNode
) => void;
assignClassToSelf: (destType: ClassType, srcType: ClassType, assumedVariance: Variance) => boolean; assignClassToSelf: (destType: ClassType, srcType: ClassType, assumedVariance: Variance) => boolean;
getBuiltInObject: (node: ParseNode, name: string, typeArguments?: Type[]) => Type; getBuiltInObject: (node: ParseNode, name: string, typeArguments?: Type[]) => Type;
getTypedDictClassType: () => ClassType | undefined; getTypedDictClassType: () => ClassType | undefined;