mirror of
https://github.com/microsoft/pyright.git
synced 2024-10-05 12:27:30 +03:00
Changed tuple expression inference behavior to not preserve literal entry types if the tuple expression is embedded within another tuple, set, list, or dictionary expression. This addresses #7159. (#7970)
This commit is contained in:
parent
0618acc535
commit
50d4f44735
@ -261,11 +261,11 @@ var1 = [4]
|
|||||||
When inferring the type of a tuple expression (in the absence of bidirectional inference hints), Pyright assumes that the tuple has a fixed length, and each tuple element is typed as specifically as possible.
|
When inferring the type of a tuple expression (in the absence of bidirectional inference hints), Pyright assumes that the tuple has a fixed length, and each tuple element is typed as specifically as possible.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# The inferred type is tuple[Literal[1], Literal["a"], Literal[True]]
|
# The inferred type is tuple[Literal[1], Literal["a"], Literal[True]].
|
||||||
var1 = (1, "a", True)
|
var1 = (1, "a", True)
|
||||||
|
|
||||||
def func1(a: int):
|
def func1(a: int):
|
||||||
# The inferred type is tuple[int, int]
|
# The inferred type is tuple[int, int].
|
||||||
var2 = (a, a)
|
var2 = (a, a)
|
||||||
|
|
||||||
# If you want the type to be tuple[int, ...]
|
# If you want the type to be tuple[int, ...]
|
||||||
@ -274,6 +274,13 @@ def func1(a: int):
|
|||||||
var3: tuple[int, ...] = (a, a)
|
var3: tuple[int, ...] = (a, a)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Because tuples are typed as specifically as possible, literal types are normally retained. However, as an exception to this inference rule, if the tuple expression is nested within another tuple, set, list or dictionary expression, literal types are not retained. This is done to avoid the inference of complex types (e.g. unions with many subtypes) when evaluating tuple statements with many entries.
|
||||||
|
|
||||||
|
```python
|
||||||
|
# The inferred type is list[tuple[int, str, bool]].
|
||||||
|
var4 = [(1, "a", True), (2, "b", False), (3, "c", False)]
|
||||||
|
```
|
||||||
|
|
||||||
#### List Expressions
|
#### List Expressions
|
||||||
|
|
||||||
When inferring the type of a list expression (in the absence of bidirectional inference hints), Pyright uses the following heuristics:
|
When inferring the type of a list expression (in the absence of bidirectional inference hints), Pyright uses the following heuristics:
|
||||||
|
@ -1175,7 +1175,7 @@ export function createTypeEvaluator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
case ParseNodeType.ListComprehension: {
|
case ParseNodeType.ListComprehension: {
|
||||||
typeResult = getTypeOfListComprehension(node, inferenceContext);
|
typeResult = getTypeOfListComprehension(node, flags, inferenceContext);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7826,6 +7826,12 @@ export function createTypeEvaluator(
|
|||||||
return { type: makeTupleObject([]), isEmptyTupleShorthand: true };
|
return { type: makeTupleObject([]), isEmptyTupleShorthand: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flags &= ~(
|
||||||
|
EvaluatorFlags.ExpectingTypeAnnotation |
|
||||||
|
EvaluatorFlags.EvaluateStringLiteralAsType |
|
||||||
|
EvaluatorFlags.ExpectingInstantiableType
|
||||||
|
);
|
||||||
|
|
||||||
// If the expected type is a union, recursively call for each of the subtypes
|
// If the expected type is a union, recursively call for each of the subtypes
|
||||||
// to find one that matches.
|
// to find one that matches.
|
||||||
let effectiveExpectedType = inferenceContext?.expectedType;
|
let effectiveExpectedType = inferenceContext?.expectedType;
|
||||||
@ -7845,6 +7851,7 @@ export function createTypeEvaluator(
|
|||||||
const subtypeResult = useSpeculativeMode(node, () => {
|
const subtypeResult = useSpeculativeMode(node, () => {
|
||||||
return getTypeOfTupleWithContext(
|
return getTypeOfTupleWithContext(
|
||||||
node,
|
node,
|
||||||
|
flags,
|
||||||
makeInferenceContext(subtype),
|
makeInferenceContext(subtype),
|
||||||
/* signatureTracker */ undefined
|
/* signatureTracker */ undefined
|
||||||
);
|
);
|
||||||
@ -7865,6 +7872,7 @@ export function createTypeEvaluator(
|
|||||||
if (effectiveExpectedType) {
|
if (effectiveExpectedType) {
|
||||||
const result = getTypeOfTupleWithContext(
|
const result = getTypeOfTupleWithContext(
|
||||||
node,
|
node,
|
||||||
|
flags,
|
||||||
makeInferenceContext(effectiveExpectedType),
|
makeInferenceContext(effectiveExpectedType),
|
||||||
signatureTracker
|
signatureTracker
|
||||||
);
|
);
|
||||||
@ -7876,7 +7884,7 @@ export function createTypeEvaluator(
|
|||||||
expectedTypeDiagAddendum = result?.expectedTypeDiagAddendum;
|
expectedTypeDiagAddendum = result?.expectedTypeDiagAddendum;
|
||||||
}
|
}
|
||||||
|
|
||||||
const typeResult = getTypeOfTupleInferred(node);
|
const typeResult = getTypeOfTupleInferred(node, flags);
|
||||||
|
|
||||||
// If there was an expected type of Any, replace the resulting type
|
// If there was an expected type of Any, replace the resulting type
|
||||||
// with Any rather than return a type with unknowns.
|
// with Any rather than return a type with unknowns.
|
||||||
@ -7889,6 +7897,7 @@ export function createTypeEvaluator(
|
|||||||
|
|
||||||
function getTypeOfTupleWithContext(
|
function getTypeOfTupleWithContext(
|
||||||
node: TupleNode,
|
node: TupleNode,
|
||||||
|
flags: EvaluatorFlags,
|
||||||
inferenceContext: InferenceContext,
|
inferenceContext: InferenceContext,
|
||||||
signatureTracker: UniqueSignatureTracker | undefined
|
signatureTracker: UniqueSignatureTracker | undefined
|
||||||
): TypeResult | undefined {
|
): TypeResult | undefined {
|
||||||
@ -7947,7 +7956,7 @@ export function createTypeEvaluator(
|
|||||||
const entryTypeResults = node.expressions.map((expr, index) =>
|
const entryTypeResults = node.expressions.map((expr, index) =>
|
||||||
getTypeOfExpression(
|
getTypeOfExpression(
|
||||||
expr,
|
expr,
|
||||||
/* flags */ undefined,
|
flags | EvaluatorFlags.StripLiteralTypeForTuple,
|
||||||
makeInferenceContext(
|
makeInferenceContext(
|
||||||
index < expectedTypes.length ? expectedTypes[index] : undefined,
|
index < expectedTypes.length ? expectedTypes[index] : undefined,
|
||||||
inferenceContext.isTypeIncomplete
|
inferenceContext.isTypeIncomplete
|
||||||
@ -7956,7 +7965,7 @@ export function createTypeEvaluator(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
const isIncomplete = entryTypeResults.some((result) => result.isIncomplete);
|
const isIncomplete = entryTypeResults.some((result) => result.isIncomplete);
|
||||||
const type = makeTupleObject(buildTupleTypesList(entryTypeResults));
|
const type = makeTupleObject(buildTupleTypesList(entryTypeResults, /* stripLiterals */ false));
|
||||||
|
|
||||||
// Copy any expected type diag addenda for precision error reporting.
|
// Copy any expected type diag addenda for precision error reporting.
|
||||||
let expectedTypeDiagAddendum: DiagnosticAddendum | undefined;
|
let expectedTypeDiagAddendum: DiagnosticAddendum | undefined;
|
||||||
@ -7972,11 +7981,15 @@ export function createTypeEvaluator(
|
|||||||
return { type, expectedTypeDiagAddendum, isIncomplete };
|
return { type, expectedTypeDiagAddendum, isIncomplete };
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTypeOfTupleInferred(node: TupleNode): TypeResult {
|
function getTypeOfTupleInferred(node: TupleNode, flags: EvaluatorFlags): TypeResult {
|
||||||
const entryTypeResults = node.expressions.map((expr) => getTypeOfExpression(expr));
|
const entryTypeResults = node.expressions.map((expr) =>
|
||||||
|
getTypeOfExpression(expr, flags | EvaluatorFlags.StripLiteralTypeForTuple)
|
||||||
|
);
|
||||||
const isIncomplete = entryTypeResults.some((result) => result.isIncomplete);
|
const isIncomplete = entryTypeResults.some((result) => result.isIncomplete);
|
||||||
|
|
||||||
const type = makeTupleObject(buildTupleTypesList(entryTypeResults));
|
const type = makeTupleObject(
|
||||||
|
buildTupleTypesList(entryTypeResults, (flags & EvaluatorFlags.StripLiteralTypeForTuple) !== 0)
|
||||||
|
);
|
||||||
|
|
||||||
if (isIncomplete) {
|
if (isIncomplete) {
|
||||||
if (getContainerDepth(type) > maxInferredContainerDepth) {
|
if (getContainerDepth(type) > maxInferredContainerDepth) {
|
||||||
@ -7987,7 +8000,7 @@ export function createTypeEvaluator(
|
|||||||
return { type, isIncomplete };
|
return { type, isIncomplete };
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildTupleTypesList(entryTypeResults: TypeResult[]): TupleTypeArgument[] {
|
function buildTupleTypesList(entryTypeResults: TypeResult[], stripLiterals: boolean): TupleTypeArgument[] {
|
||||||
const entryTypes: TupleTypeArgument[] = [];
|
const entryTypes: TupleTypeArgument[] = [];
|
||||||
|
|
||||||
for (const typeResult of entryTypeResults) {
|
for (const typeResult of entryTypeResults) {
|
||||||
@ -8017,7 +8030,8 @@ export function createTypeEvaluator(
|
|||||||
} else if (isNever(typeResult.type) && typeResult.isIncomplete && !typeResult.unpackedType) {
|
} else if (isNever(typeResult.type) && typeResult.isIncomplete && !typeResult.unpackedType) {
|
||||||
entryTypes.push({ type: UnknownType.create(/* isIncomplete */ true), isUnbounded: false });
|
entryTypes.push({ type: UnknownType.create(/* isIncomplete */ true), isUnbounded: false });
|
||||||
} else {
|
} else {
|
||||||
entryTypes.push({ type: typeResult.type, isUnbounded: !!typeResult.unpackedType });
|
const entryType = stripLiterals ? stripLiteralValue(typeResult.type) : typeResult.type;
|
||||||
|
entryTypes.push({ type: entryType, isUnbounded: !!typeResult.unpackedType });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13318,7 +13332,7 @@ export function createTypeEvaluator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const subtypeResult = useSpeculativeMode(node, () => {
|
const subtypeResult = useSpeculativeMode(node, () => {
|
||||||
return getTypeOfDictionaryWithContext(node, makeInferenceContext(subtype));
|
return getTypeOfDictionaryWithContext(node, flags, makeInferenceContext(subtype));
|
||||||
});
|
});
|
||||||
|
|
||||||
if (subtypeResult && assignType(subtype, subtypeResult.type)) {
|
if (subtypeResult && assignType(subtype, subtypeResult.type)) {
|
||||||
@ -13341,6 +13355,7 @@ export function createTypeEvaluator(
|
|||||||
expectedTypeDiagAddendum = new DiagnosticAddendum();
|
expectedTypeDiagAddendum = new DiagnosticAddendum();
|
||||||
const result = getTypeOfDictionaryWithContext(
|
const result = getTypeOfDictionaryWithContext(
|
||||||
node,
|
node,
|
||||||
|
flags,
|
||||||
makeInferenceContext(effectiveExpectedType),
|
makeInferenceContext(effectiveExpectedType),
|
||||||
expectedTypeDiagAddendum
|
expectedTypeDiagAddendum
|
||||||
);
|
);
|
||||||
@ -13349,12 +13364,13 @@ export function createTypeEvaluator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = getTypeOfDictionaryInferred(node, /* hasExpectedType */ !!inferenceContext);
|
const result = getTypeOfDictionaryInferred(node, flags, /* hasExpectedType */ !!inferenceContext);
|
||||||
return { ...result, expectedTypeDiagAddendum };
|
return { ...result, expectedTypeDiagAddendum };
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTypeOfDictionaryWithContext(
|
function getTypeOfDictionaryWithContext(
|
||||||
node: DictionaryNode,
|
node: DictionaryNode,
|
||||||
|
flags: EvaluatorFlags,
|
||||||
inferenceContext: InferenceContext,
|
inferenceContext: InferenceContext,
|
||||||
expectedDiagAddendum?: DiagnosticAddendum
|
expectedDiagAddendum?: DiagnosticAddendum
|
||||||
): TypeResult | undefined {
|
): TypeResult | undefined {
|
||||||
@ -13381,6 +13397,7 @@ export function createTypeEvaluator(
|
|||||||
// Infer the key and value types if possible.
|
// Infer the key and value types if possible.
|
||||||
const keyValueTypeResult = getKeyAndValueTypesFromDictionary(
|
const keyValueTypeResult = getKeyAndValueTypesFromDictionary(
|
||||||
node,
|
node,
|
||||||
|
flags,
|
||||||
keyTypes,
|
keyTypes,
|
||||||
valueTypes,
|
valueTypes,
|
||||||
/* forceStrictInference */ true,
|
/* forceStrictInference */ true,
|
||||||
@ -13472,6 +13489,7 @@ export function createTypeEvaluator(
|
|||||||
// Infer the key and value types if possible.
|
// Infer the key and value types if possible.
|
||||||
const keyValueResult = getKeyAndValueTypesFromDictionary(
|
const keyValueResult = getKeyAndValueTypesFromDictionary(
|
||||||
node,
|
node,
|
||||||
|
flags,
|
||||||
keyTypes,
|
keyTypes,
|
||||||
valueTypes,
|
valueTypes,
|
||||||
/* forceStrictInference */ true,
|
/* forceStrictInference */ true,
|
||||||
@ -13510,7 +13528,11 @@ export function createTypeEvaluator(
|
|||||||
|
|
||||||
// Attempts to infer the type of a dictionary statement. If hasExpectedType
|
// Attempts to infer the type of a dictionary statement. If hasExpectedType
|
||||||
// is true, strict inference is used for the subexpressions.
|
// is true, strict inference is used for the subexpressions.
|
||||||
function getTypeOfDictionaryInferred(node: DictionaryNode, hasExpectedType: boolean): TypeResult {
|
function getTypeOfDictionaryInferred(
|
||||||
|
node: DictionaryNode,
|
||||||
|
flags: EvaluatorFlags,
|
||||||
|
hasExpectedType: boolean
|
||||||
|
): TypeResult {
|
||||||
const fallbackType = hasExpectedType ? AnyType.create() : UnknownType.create();
|
const fallbackType = hasExpectedType ? AnyType.create() : UnknownType.create();
|
||||||
let keyType: Type = fallbackType;
|
let keyType: Type = fallbackType;
|
||||||
let valueType: Type = fallbackType;
|
let valueType: Type = fallbackType;
|
||||||
@ -13525,6 +13547,7 @@ export function createTypeEvaluator(
|
|||||||
// Infer the key and value types if possible.
|
// Infer the key and value types if possible.
|
||||||
const keyValueResult = getKeyAndValueTypesFromDictionary(
|
const keyValueResult = getKeyAndValueTypesFromDictionary(
|
||||||
node,
|
node,
|
||||||
|
flags,
|
||||||
keyTypeResults,
|
keyTypeResults,
|
||||||
valueTypeResults,
|
valueTypeResults,
|
||||||
/* forceStrictInference */ hasExpectedType,
|
/* forceStrictInference */ hasExpectedType,
|
||||||
@ -13586,6 +13609,7 @@ export function createTypeEvaluator(
|
|||||||
|
|
||||||
function getKeyAndValueTypesFromDictionary(
|
function getKeyAndValueTypesFromDictionary(
|
||||||
node: DictionaryNode,
|
node: DictionaryNode,
|
||||||
|
flags: EvaluatorFlags,
|
||||||
keyTypes: TypeResultWithNode[],
|
keyTypes: TypeResultWithNode[],
|
||||||
valueTypes: TypeResultWithNode[],
|
valueTypes: TypeResultWithNode[],
|
||||||
forceStrictInference: boolean,
|
forceStrictInference: boolean,
|
||||||
@ -13598,6 +13622,16 @@ export function createTypeEvaluator(
|
|||||||
let isIncomplete = false;
|
let isIncomplete = false;
|
||||||
let typeErrors = false;
|
let typeErrors = false;
|
||||||
|
|
||||||
|
// Mask out some of the flags that are not applicable for a dictionary key
|
||||||
|
// even if it appears within an inlined TypedDict annotation.
|
||||||
|
const keyFlags =
|
||||||
|
flags &
|
||||||
|
~(
|
||||||
|
EvaluatorFlags.ExpectingTypeAnnotation |
|
||||||
|
EvaluatorFlags.EvaluateStringLiteralAsType |
|
||||||
|
EvaluatorFlags.ExpectingInstantiableType
|
||||||
|
);
|
||||||
|
|
||||||
// Infer the key and value types if possible.
|
// Infer the key and value types if possible.
|
||||||
node.entries.forEach((entryNode, index) => {
|
node.entries.forEach((entryNode, index) => {
|
||||||
let addUnknown = true;
|
let addUnknown = true;
|
||||||
@ -13605,7 +13639,7 @@ export function createTypeEvaluator(
|
|||||||
if (entryNode.nodeType === ParseNodeType.DictionaryKeyEntry) {
|
if (entryNode.nodeType === ParseNodeType.DictionaryKeyEntry) {
|
||||||
const keyTypeResult = getTypeOfExpression(
|
const keyTypeResult = getTypeOfExpression(
|
||||||
entryNode.keyExpression,
|
entryNode.keyExpression,
|
||||||
/* flags */ undefined,
|
keyFlags | EvaluatorFlags.StripLiteralTypeForTuple,
|
||||||
makeInferenceContext(
|
makeInferenceContext(
|
||||||
expectedKeyType ?? (forceStrictInference ? NeverType.createNever() : undefined)
|
expectedKeyType ?? (forceStrictInference ? NeverType.createNever() : undefined)
|
||||||
)
|
)
|
||||||
@ -13645,7 +13679,7 @@ export function createTypeEvaluator(
|
|||||||
entryInferenceContext = makeInferenceContext(effectiveValueType);
|
entryInferenceContext = makeInferenceContext(effectiveValueType);
|
||||||
valueTypeResult = getTypeOfExpression(
|
valueTypeResult = getTypeOfExpression(
|
||||||
entryNode.valueExpression,
|
entryNode.valueExpression,
|
||||||
/* flags */ undefined,
|
flags | EvaluatorFlags.StripLiteralTypeForTuple,
|
||||||
entryInferenceContext
|
entryInferenceContext
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -13654,7 +13688,7 @@ export function createTypeEvaluator(
|
|||||||
entryInferenceContext = makeInferenceContext(effectiveValueType);
|
entryInferenceContext = makeInferenceContext(effectiveValueType);
|
||||||
valueTypeResult = getTypeOfExpression(
|
valueTypeResult = getTypeOfExpression(
|
||||||
entryNode.valueExpression,
|
entryNode.valueExpression,
|
||||||
/* flags */ undefined,
|
flags | EvaluatorFlags.StripLiteralTypeForTuple,
|
||||||
entryInferenceContext
|
entryInferenceContext
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -13717,7 +13751,7 @@ export function createTypeEvaluator(
|
|||||||
const entryInferenceContext = makeInferenceContext(expectedType);
|
const entryInferenceContext = makeInferenceContext(expectedType);
|
||||||
let unexpandedTypeResult = getTypeOfExpression(
|
let unexpandedTypeResult = getTypeOfExpression(
|
||||||
entryNode.expandExpression,
|
entryNode.expandExpression,
|
||||||
/* flags */ undefined,
|
flags | EvaluatorFlags.StripLiteralTypeForTuple,
|
||||||
entryInferenceContext
|
entryInferenceContext
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -13817,6 +13851,7 @@ export function createTypeEvaluator(
|
|||||||
} else if (entryNode.nodeType === ParseNodeType.ListComprehension) {
|
} else if (entryNode.nodeType === ParseNodeType.ListComprehension) {
|
||||||
const dictEntryTypeResult = getElementTypeFromListComprehension(
|
const dictEntryTypeResult = getElementTypeFromListComprehension(
|
||||||
entryNode,
|
entryNode,
|
||||||
|
flags,
|
||||||
expectedValueType,
|
expectedValueType,
|
||||||
expectedKeyType
|
expectedKeyType
|
||||||
);
|
);
|
||||||
@ -13868,6 +13903,12 @@ export function createTypeEvaluator(
|
|||||||
addDiagnostic(DiagnosticRule.reportInvalidTypeForm, LocMessage.listInAnnotation() + diag.getString(), node);
|
addDiagnostic(DiagnosticRule.reportInvalidTypeForm, LocMessage.listInAnnotation() + diag.getString(), node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flags &= ~(
|
||||||
|
EvaluatorFlags.ExpectingTypeAnnotation |
|
||||||
|
EvaluatorFlags.EvaluateStringLiteralAsType |
|
||||||
|
EvaluatorFlags.ExpectingInstantiableType
|
||||||
|
);
|
||||||
|
|
||||||
// If the expected type is a union, recursively call for each of the subtypes
|
// If the expected type is a union, recursively call for each of the subtypes
|
||||||
// to find one that matches.
|
// to find one that matches.
|
||||||
let effectiveExpectedType = inferenceContext?.expectedType;
|
let effectiveExpectedType = inferenceContext?.expectedType;
|
||||||
@ -13885,7 +13926,7 @@ export function createTypeEvaluator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const subtypeResult = useSpeculativeMode(node, () => {
|
const subtypeResult = useSpeculativeMode(node, () => {
|
||||||
return getTypeOfListOrSetWithContext(node, makeInferenceContext(subtype));
|
return getTypeOfListOrSetWithContext(node, flags, makeInferenceContext(subtype));
|
||||||
});
|
});
|
||||||
|
|
||||||
if (subtypeResult && assignType(subtype, subtypeResult.type)) {
|
if (subtypeResult && assignType(subtype, subtypeResult.type)) {
|
||||||
@ -13905,7 +13946,7 @@ export function createTypeEvaluator(
|
|||||||
|
|
||||||
let expectedTypeDiagAddendum: DiagnosticAddendum | undefined;
|
let expectedTypeDiagAddendum: DiagnosticAddendum | undefined;
|
||||||
if (effectiveExpectedType) {
|
if (effectiveExpectedType) {
|
||||||
const result = getTypeOfListOrSetWithContext(node, makeInferenceContext(effectiveExpectedType));
|
const result = getTypeOfListOrSetWithContext(node, flags, makeInferenceContext(effectiveExpectedType));
|
||||||
if (result && !result.typeErrors) {
|
if (result && !result.typeErrors) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -13913,7 +13954,11 @@ export function createTypeEvaluator(
|
|||||||
expectedTypeDiagAddendum = result?.expectedTypeDiagAddendum;
|
expectedTypeDiagAddendum = result?.expectedTypeDiagAddendum;
|
||||||
}
|
}
|
||||||
|
|
||||||
const typeResult = getTypeOfListOrSetInferred(node, /* hasExpectedType */ inferenceContext !== undefined);
|
const typeResult = getTypeOfListOrSetInferred(
|
||||||
|
node,
|
||||||
|
flags,
|
||||||
|
/* hasExpectedType */ inferenceContext !== undefined
|
||||||
|
);
|
||||||
return { ...typeResult, expectedTypeDiagAddendum };
|
return { ...typeResult, expectedTypeDiagAddendum };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13921,6 +13966,7 @@ export function createTypeEvaluator(
|
|||||||
// Returns undefined if that type cannot be honored.
|
// Returns undefined if that type cannot be honored.
|
||||||
function getTypeOfListOrSetWithContext(
|
function getTypeOfListOrSetWithContext(
|
||||||
node: ListNode | SetNode,
|
node: ListNode | SetNode,
|
||||||
|
flags: EvaluatorFlags,
|
||||||
inferenceContext: InferenceContext
|
inferenceContext: InferenceContext
|
||||||
): TypeResult | undefined {
|
): TypeResult | undefined {
|
||||||
const builtInClassName = node.nodeType === ParseNodeType.List ? 'list' : 'set';
|
const builtInClassName = node.nodeType === ParseNodeType.List ? 'list' : 'set';
|
||||||
@ -13945,11 +13991,11 @@ export function createTypeEvaluator(
|
|||||||
let entryTypeResult: TypeResult;
|
let entryTypeResult: TypeResult;
|
||||||
|
|
||||||
if (entry.nodeType === ParseNodeType.ListComprehension) {
|
if (entry.nodeType === ParseNodeType.ListComprehension) {
|
||||||
entryTypeResult = getElementTypeFromListComprehension(entry, expectedEntryType);
|
entryTypeResult = getElementTypeFromListComprehension(entry, flags, expectedEntryType);
|
||||||
} else {
|
} else {
|
||||||
entryTypeResult = getTypeOfExpression(
|
entryTypeResult = getTypeOfExpression(
|
||||||
entry,
|
entry,
|
||||||
/* flags */ undefined,
|
flags | EvaluatorFlags.StripLiteralTypeForTuple,
|
||||||
makeInferenceContext(expectedEntryType)
|
makeInferenceContext(expectedEntryType)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -14044,7 +14090,11 @@ export function createTypeEvaluator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attempts to infer the type of a list or set statement with no "expected type".
|
// Attempts to infer the type of a list or set statement with no "expected type".
|
||||||
function getTypeOfListOrSetInferred(node: ListNode | SetNode, hasExpectedType: boolean): TypeResult {
|
function getTypeOfListOrSetInferred(
|
||||||
|
node: ListNode | SetNode,
|
||||||
|
flags: EvaluatorFlags,
|
||||||
|
hasExpectedType: boolean
|
||||||
|
): TypeResult {
|
||||||
const builtInClassName = node.nodeType === ParseNodeType.List ? 'list' : 'set';
|
const builtInClassName = node.nodeType === ParseNodeType.List ? 'list' : 'set';
|
||||||
const verifyHashable = node.nodeType === ParseNodeType.Set;
|
const verifyHashable = node.nodeType === ParseNodeType.Set;
|
||||||
let isEmptyContainer = false;
|
let isEmptyContainer = false;
|
||||||
@ -14056,9 +14106,9 @@ export function createTypeEvaluator(
|
|||||||
let entryTypeResult: TypeResult;
|
let entryTypeResult: TypeResult;
|
||||||
|
|
||||||
if (entry.nodeType === ParseNodeType.ListComprehension && !entry.isGenerator) {
|
if (entry.nodeType === ParseNodeType.ListComprehension && !entry.isGenerator) {
|
||||||
entryTypeResult = getElementTypeFromListComprehension(entry);
|
entryTypeResult = getElementTypeFromListComprehension(entry, flags);
|
||||||
} else {
|
} else {
|
||||||
entryTypeResult = getTypeOfExpression(entry);
|
entryTypeResult = getTypeOfExpression(entry, flags | EvaluatorFlags.StripLiteralTypeForTuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entryTypeResult.isIncomplete) {
|
if (entryTypeResult.isIncomplete) {
|
||||||
@ -14479,7 +14529,11 @@ export function createTypeEvaluator(
|
|||||||
return { type: functionType, isIncomplete, typeErrors };
|
return { type: functionType, isIncomplete, typeErrors };
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTypeOfListComprehension(node: ListComprehensionNode, inferenceContext?: InferenceContext): TypeResult {
|
function getTypeOfListComprehension(
|
||||||
|
node: ListComprehensionNode,
|
||||||
|
flags: EvaluatorFlags,
|
||||||
|
inferenceContext?: InferenceContext
|
||||||
|
): TypeResult {
|
||||||
let isIncomplete = false;
|
let isIncomplete = false;
|
||||||
let typeErrors = false;
|
let typeErrors = false;
|
||||||
|
|
||||||
@ -14501,7 +14555,7 @@ export function createTypeEvaluator(
|
|||||||
const builtInIteratorType = getTypingType(node, isAsync ? 'AsyncGenerator' : 'Generator');
|
const builtInIteratorType = getTypingType(node, isAsync ? 'AsyncGenerator' : 'Generator');
|
||||||
|
|
||||||
const expectedEntryType = getExpectedEntryTypeForIterable(node, builtInIteratorType, inferenceContext);
|
const expectedEntryType = getExpectedEntryTypeForIterable(node, builtInIteratorType, inferenceContext);
|
||||||
const elementTypeResult = getElementTypeFromListComprehension(node, expectedEntryType);
|
const elementTypeResult = getElementTypeFromListComprehension(node, flags, expectedEntryType);
|
||||||
if (elementTypeResult.isIncomplete) {
|
if (elementTypeResult.isIncomplete) {
|
||||||
isIncomplete = true;
|
isIncomplete = true;
|
||||||
}
|
}
|
||||||
@ -14610,6 +14664,7 @@ export function createTypeEvaluator(
|
|||||||
// as opposed to the entire list.
|
// as opposed to the entire list.
|
||||||
function getElementTypeFromListComprehension(
|
function getElementTypeFromListComprehension(
|
||||||
node: ListComprehensionNode,
|
node: ListComprehensionNode,
|
||||||
|
flags: EvaluatorFlags,
|
||||||
expectedValueOrElementType?: Type,
|
expectedValueOrElementType?: Type,
|
||||||
expectedKeyType?: Type
|
expectedKeyType?: Type
|
||||||
): TypeResult {
|
): TypeResult {
|
||||||
@ -14628,7 +14683,7 @@ export function createTypeEvaluator(
|
|||||||
// Create a tuple with the key/value types.
|
// Create a tuple with the key/value types.
|
||||||
const keyTypeResult = getTypeOfExpression(
|
const keyTypeResult = getTypeOfExpression(
|
||||||
node.expression.keyExpression,
|
node.expression.keyExpression,
|
||||||
/* flags */ undefined,
|
flags | EvaluatorFlags.StripLiteralTypeForTuple,
|
||||||
makeInferenceContext(expectedKeyType)
|
makeInferenceContext(expectedKeyType)
|
||||||
);
|
);
|
||||||
if (keyTypeResult.isIncomplete) {
|
if (keyTypeResult.isIncomplete) {
|
||||||
@ -14644,7 +14699,7 @@ export function createTypeEvaluator(
|
|||||||
|
|
||||||
const valueTypeResult = getTypeOfExpression(
|
const valueTypeResult = getTypeOfExpression(
|
||||||
node.expression.valueExpression,
|
node.expression.valueExpression,
|
||||||
/* flags */ undefined,
|
flags | EvaluatorFlags.StripLiteralTypeForTuple,
|
||||||
makeInferenceContext(expectedValueOrElementType)
|
makeInferenceContext(expectedValueOrElementType)
|
||||||
);
|
);
|
||||||
if (valueTypeResult.isIncomplete) {
|
if (valueTypeResult.isIncomplete) {
|
||||||
@ -14666,13 +14721,13 @@ export function createTypeEvaluator(
|
|||||||
// The parser should have reported an error in this case because it's not allowed.
|
// The parser should have reported an error in this case because it's not allowed.
|
||||||
getTypeOfExpression(
|
getTypeOfExpression(
|
||||||
node.expression.expandExpression,
|
node.expression.expandExpression,
|
||||||
/* flags */ undefined,
|
flags | EvaluatorFlags.StripLiteralTypeForTuple,
|
||||||
makeInferenceContext(expectedValueOrElementType)
|
makeInferenceContext(expectedValueOrElementType)
|
||||||
);
|
);
|
||||||
} else if (isExpressionNode(node)) {
|
} else if (isExpressionNode(node)) {
|
||||||
const exprTypeResult = getTypeOfExpression(
|
const exprTypeResult = getTypeOfExpression(
|
||||||
node.expression as ExpressionNode,
|
node.expression as ExpressionNode,
|
||||||
/* flags */ undefined,
|
flags | EvaluatorFlags.StripLiteralTypeForTuple,
|
||||||
makeInferenceContext(expectedValueOrElementType)
|
makeInferenceContext(expectedValueOrElementType)
|
||||||
);
|
);
|
||||||
if (exprTypeResult.isIncomplete) {
|
if (exprTypeResult.isIncomplete) {
|
||||||
|
@ -154,6 +154,10 @@ export const enum EvaluatorFlags {
|
|||||||
// Allow use of the Concatenate special form.
|
// Allow use of the Concatenate special form.
|
||||||
AllowConcatenate = 1 << 27,
|
AllowConcatenate = 1 << 27,
|
||||||
|
|
||||||
|
// Do not infer literal types within a tuple (used for tuples nested within
|
||||||
|
// other container classes).
|
||||||
|
StripLiteralTypeForTuple = 1 << 28,
|
||||||
|
|
||||||
// Defaults used for evaluating the LHS of a call expression.
|
// Defaults used for evaluating the LHS of a call expression.
|
||||||
CallBaseDefaults = DoNotSpecialize,
|
CallBaseDefaults = DoNotSpecialize,
|
||||||
|
|
||||||
|
@ -15,4 +15,4 @@ times = [
|
|||||||
for meridian in ("am", "pm")
|
for meridian in ("am", "pm")
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
reveal_type(times, expected_text="list[tuple[int, int, Literal['am', 'pm']]]")
|
reveal_type(times, expected_text="list[tuple[int, int, str]]")
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
# This sample tests the inferred type of async and sync generators.
|
# This sample tests the inferred type of async and sync generators.
|
||||||
|
|
||||||
|
|
||||||
async def foo() -> int:
|
async def foo() -> int: ...
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
async def main() -> None:
|
async def main() -> None:
|
||||||
@ -19,7 +18,7 @@ async def main() -> None:
|
|||||||
reveal_type(v4, expected_text="AsyncGenerator[int, None]")
|
reveal_type(v4, expected_text="AsyncGenerator[int, None]")
|
||||||
|
|
||||||
v5 = ((0, await foo()) for _ in [1, 2])
|
v5 = ((0, await foo()) for _ in [1, 2])
|
||||||
reveal_type(v5, expected_text="AsyncGenerator[tuple[Literal[0], int], None]")
|
reveal_type(v5, expected_text="AsyncGenerator[tuple[int, int], None]")
|
||||||
|
|
||||||
v6 = (x for x in [1, 2] if (x, await foo()))
|
v6 = (x for x in [1, 2] if (x, await foo()))
|
||||||
reveal_type(v6, expected_text="AsyncGenerator[int, None]")
|
reveal_type(v6, expected_text="AsyncGenerator[int, None]")
|
||||||
|
@ -742,7 +742,7 @@ test('TypedDictInline1', () => {
|
|||||||
configOptions.diagnosticRuleSet.enableExperimentalFeatures = true;
|
configOptions.diagnosticRuleSet.enableExperimentalFeatures = true;
|
||||||
|
|
||||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typedDictInline1.py'], configOptions);
|
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typedDictInline1.py'], configOptions);
|
||||||
TestUtils.validateResults(analysisResults, 8);
|
TestUtils.validateResults(analysisResults, 9);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ClassVar1', () => {
|
test('ClassVar1', () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user