Added logic to expand promotion types for float and complex when these types are used in a member access expression (i.e. the LHS of a "dot" operator).

This commit is contained in:
Eric Traut 2024-05-29 17:40:49 -07:00
parent 2e397e9a0a
commit 7f31936781
4 changed files with 31 additions and 7 deletions

View File

@ -122,6 +122,12 @@ export function validateConstructorArguments(
inferenceContext: InferenceContext | undefined,
signatureTracker: UniqueSignatureTracker | undefined
): CallResult {
// If this is a "float" or "complex" constructor call, do not include
// the associated promotions.
if (!type.includeSubclasses && type.includePromotions) {
type = ClassType.cloneRemoveTypePromotions(type);
}
const metaclassResult = validateMetaclassCall(
evaluator,
errorNode,

View File

@ -5226,6 +5226,11 @@ export function createTypeEvaluator(
baseType = makeTopLevelTypeVarsConcrete(baseType);
}
// Do union expansion for promotion types. Exclude bytes here because
// this creates too much noise. Users who want stricter checks for bytes
// can use "disableBytesTypePromotions".
baseType = expandPromotionTypes(node, baseType, /* excludeBytes */ true);
switch (baseType.category) {
case TypeCategory.Any:
case TypeCategory.Unknown:

View File

@ -1346,6 +1346,12 @@ function narrowTypeForIsInstanceInternal(
let filterIsSuperclass: boolean;
let filterIsSubclass: boolean;
// If the user has explicitly specified "float" or "complex" as a filter,
// eliminate the associated promotions.
if (!concreteFilterType.includeSubclasses && concreteFilterType.includePromotions) {
concreteFilterType = ClassType.cloneRemoveTypePromotions(concreteFilterType);
}
if (isTypeIsCheck) {
filterIsSuperclass = evaluator.assignType(filterType, concreteVarType);
filterIsSubclass = evaluator.assignType(concreteVarType, filterType);
@ -1775,21 +1781,28 @@ function narrowTypeForIsInstanceInternal(
const isSubtypeMetaclass = isMetaclassInstance(subtype);
if (isPositiveTest && isAnyOrUnknown(subtype)) {
const filterTypeInstances = filterTypes.map((filterType) => {
if (
isInstantiableClass(filterType) &&
!filterType.includeSubclasses &&
filterType.includePromotions
) {
filterType = ClassType.cloneRemoveTypePromotions(filterType);
}
return convertToInstance(filterType);
});
// If this is a positive test and the effective type is Any or
// Unknown, we can assume that the type matches one of the
// specified types.
if (isInstanceCheck) {
anyOrUnknownSubstitutions.push(
combineTypes(filterTypes.map((classType) => convertToInstance(classType)))
);
anyOrUnknownSubstitutions.push(combineTypes(filterTypeInstances));
} else {
// We perform a double conversion from instance to instantiable
// here to make sure that the includeSubclasses flag is cleared
// if it's a class.
anyOrUnknownSubstitutions.push(
combineTypes(
filterTypes.map((classType) => convertToInstantiable(convertToInstance(classType)))
)
combineTypes(filterTypeInstances.map((classType) => convertToInstantiable(classType)))
);
}

View File

@ -15,7 +15,7 @@ b1: int = b["x"]
b2: float = b["x"]
c = dict(x=m, y=n)
reveal_type(c, expected_text="dict[str, float]")
reveal_type(c, expected_text="dict[str, int | float]")
# This should generate an error.
c1: int = c["x"]