mirror of
https://github.com/microsoft/pyright.git
synced 2024-09-11 07:55:56 +03:00
Added support for parameter type inference for lambdas whose parameters include default arguments. This is analogous to the logic used for unannotated function parameters with default arguments. This addresses #6558. (#6563)
This commit is contained in:
parent
f7e247986f
commit
5b3523ff53
@ -225,6 +225,13 @@ def func(a, b=0, c=None):
|
||||
reveal_type(func) # (a: Unknown, b: int, c: Unknown | None) -> None
|
||||
```
|
||||
|
||||
This inference technique also applies to lambdas whose input parameters include default arguments.
|
||||
|
||||
```python
|
||||
cb = lambda x = "": x
|
||||
reveal_type(cb) # (x: str = "" -> str)
|
||||
```
|
||||
|
||||
#### Literals
|
||||
|
||||
Python 3.8 introduced support for _literal types_. This allows a type checker like Pyright to track specific literal values of str, bytes, int, bool, and enum values. As with other types, literal types can be declared.
|
||||
|
@ -13835,6 +13835,10 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
// its type from the default value expression.
|
||||
paramType = getTypeOfExpression(param.defaultValue, undefined, inferenceContext).type;
|
||||
}
|
||||
} else if (param.defaultValue) {
|
||||
// If there is no inference context but we have a default value,
|
||||
// use the default value to infer the parameter's type.
|
||||
paramType = inferParameterTypeFromDefaultValue(param.defaultValue);
|
||||
}
|
||||
|
||||
if (param.name) {
|
||||
@ -17638,6 +17642,13 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
// type from this information.
|
||||
const paramValueExpr = functionNode.parameters[paramIndex].defaultValue;
|
||||
if (paramValueExpr) {
|
||||
return inferParameterTypeFromDefaultValue(paramValueExpr);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function inferParameterTypeFromDefaultValue(paramValueExpr: ExpressionNode) {
|
||||
const defaultValueType = getTypeOfExpression(paramValueExpr, EvaluatorFlags.ConvertEllipsisToAny).type;
|
||||
|
||||
let inferredParamType: Type | undefined;
|
||||
@ -17674,7 +17685,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
}
|
||||
|
||||
if (inferredParamType) {
|
||||
const fileInfo = AnalyzerNodeInfo.getFileInfo(functionNode);
|
||||
const fileInfo = AnalyzerNodeInfo.getFileInfo(paramValueExpr);
|
||||
if (fileInfo.isInPyTypedPackage && !fileInfo.isStubFile) {
|
||||
inferredParamType = TypeBase.cloneForAmbiguousType(inferredParamType);
|
||||
}
|
||||
@ -17683,9 +17694,6 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
return inferredParamType;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// 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 keyword-arg parameter, the type
|
||||
// is wrapped in a List or Dict.
|
||||
|
9
packages/pyright-internal/src/tests/samples/lambda14.py
Normal file
9
packages/pyright-internal/src/tests/samples/lambda14.py
Normal file
@ -0,0 +1,9 @@
|
||||
# This sample tests type inference for a lambda that has no inference
|
||||
# context but has a default argument value.
|
||||
|
||||
lambda1 = lambda x="": x
|
||||
reveal_type(lambda1, expected_text='(x: str = "") -> str')
|
||||
|
||||
lambda2 = lambda x=None: x
|
||||
reveal_type(lambda2, expected_text="(x: Unknown | None = None) -> (Unknown | None)")
|
||||
|
@ -741,6 +741,12 @@ test('Lambda13', () => {
|
||||
TestUtils.validateResults(analysisResults, 0);
|
||||
});
|
||||
|
||||
test('Lambda14', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['lambda14.py']);
|
||||
|
||||
TestUtils.validateResults(analysisResults, 0);
|
||||
});
|
||||
|
||||
test('Call1', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['call1.py']);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user