Compare commits
2 Commits
ibraheem/v
...
charlie/al
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85f5039b11 | ||
|
|
96dbe609eb |
@@ -205,3 +205,93 @@ class B:
|
||||
class A(B): ...
|
||||
class B: ...
|
||||
```
|
||||
|
||||
## Default argument values
|
||||
|
||||
### Not deferred in regular files
|
||||
|
||||
```py
|
||||
# error: [unresolved-reference]
|
||||
def f(mode: int = ParseMode.test):
|
||||
pass
|
||||
|
||||
class ParseMode:
|
||||
test = 1
|
||||
```
|
||||
|
||||
### Deferred in stub files
|
||||
|
||||
Forward references in default argument values are allowed in stub files.
|
||||
|
||||
```pyi
|
||||
def f(mode: int = ParseMode.test): ...
|
||||
|
||||
class ParseMode:
|
||||
test: int
|
||||
```
|
||||
|
||||
### Undefined names are still errors in stub files
|
||||
|
||||
```pyi
|
||||
# error: [unresolved-reference]
|
||||
def f(mode: int = NeverDefined.test): ...
|
||||
```
|
||||
|
||||
## Class keyword arguments
|
||||
|
||||
### Not deferred in regular files
|
||||
|
||||
```py
|
||||
# error: [unresolved-reference]
|
||||
class Foo(metaclass=SomeMeta):
|
||||
pass
|
||||
|
||||
class SomeMeta(type):
|
||||
pass
|
||||
```
|
||||
|
||||
### Deferred in stub files
|
||||
|
||||
Forward references in class keyword arguments are allowed in stub files.
|
||||
|
||||
```pyi
|
||||
class Foo(metaclass=SomeMeta): ...
|
||||
|
||||
class SomeMeta(type): ...
|
||||
```
|
||||
|
||||
### Undefined names are still errors in stub files
|
||||
|
||||
```pyi
|
||||
# error: [unresolved-reference]
|
||||
class Foo(metaclass=NeverDefined): ...
|
||||
```
|
||||
|
||||
## Lambda default argument values
|
||||
|
||||
### Not deferred in regular files
|
||||
|
||||
```py
|
||||
# error: [unresolved-reference]
|
||||
f = lambda x=Foo(): x
|
||||
|
||||
class Foo:
|
||||
pass
|
||||
```
|
||||
|
||||
### Deferred in stub files
|
||||
|
||||
Forward references in lambda default argument values are allowed in stub files.
|
||||
|
||||
```pyi
|
||||
f = lambda x=Foo(): x
|
||||
|
||||
class Foo: ...
|
||||
```
|
||||
|
||||
### Undefined names are still errors in stub files
|
||||
|
||||
```pyi
|
||||
# error: [unresolved-reference]
|
||||
f = lambda x=NeverDefined(): x
|
||||
```
|
||||
|
||||
@@ -50,10 +50,10 @@ reveal_type(custom_builtin) # revealed: Custom
|
||||
reveal_type(str) # revealed: Unknown
|
||||
```
|
||||
|
||||
## Unknown builtin (later defined)
|
||||
## Forward reference in builtins stub
|
||||
|
||||
`foo` has a type of `Unknown` in this example, as it relies on `bar` which has not been defined at
|
||||
that point:
|
||||
In stub files, forward references are allowed in all expressions, so `foo` correctly resolves to the
|
||||
type of `bar` even though `bar` is defined later:
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
@@ -74,5 +74,5 @@ def reveal_type(obj, /): ...
|
||||
```
|
||||
|
||||
```py
|
||||
reveal_type(foo) # revealed: Unknown
|
||||
reveal_type(foo) # revealed: Literal[1]
|
||||
```
|
||||
|
||||
@@ -327,6 +327,15 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
module: &'ast ParsedModuleRef,
|
||||
) -> Self {
|
||||
let scope = region.scope(db);
|
||||
let file = scope.file(db);
|
||||
|
||||
// In stub files, all expressions are evaluated in deferred mode to allow
|
||||
// forward references. This matches Pyright's behavior.
|
||||
let deferred_state = if file.is_stub(db) {
|
||||
DeferredExpressionState::Deferred
|
||||
} else {
|
||||
DeferredExpressionState::None
|
||||
};
|
||||
|
||||
Self {
|
||||
context: InferContext::new(db, scope, module),
|
||||
@@ -335,7 +344,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
scope,
|
||||
return_types_and_ranges: vec![],
|
||||
called_functions: FxIndexSet::default(),
|
||||
deferred_state: DeferredExpressionState::None,
|
||||
deferred_state,
|
||||
multi_inference_state: MultiInferenceState::Panic,
|
||||
inner_expression_inference_state: InnerExpressionInferenceState::Infer,
|
||||
expressions: FxHashMap::default(),
|
||||
@@ -1955,9 +1964,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
self.infer_type_parameters(type_params);
|
||||
|
||||
if let Some(arguments) = class.arguments.as_deref() {
|
||||
let in_stub = self.in_stub();
|
||||
let previous_deferred_state =
|
||||
std::mem::replace(&mut self.deferred_state, in_stub.into());
|
||||
let mut call_arguments =
|
||||
CallArguments::from_arguments(arguments, |argument, splatted_value| {
|
||||
let ty = self.infer_expression(splatted_value, TypeContext::default());
|
||||
@@ -1968,7 +1974,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
});
|
||||
let argument_forms = vec![Some(ParameterForm::Value); call_arguments.len()];
|
||||
self.infer_argument_types(arguments, &mut call_arguments, &argument_forms);
|
||||
self.deferred_state = previous_deferred_state;
|
||||
}
|
||||
|
||||
self.typevar_binding_context = previous_typevar_binding_context;
|
||||
@@ -5913,13 +5918,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
self.dataclass_field_specifiers = specifiers;
|
||||
}
|
||||
|
||||
// We defer the r.h.s. of PEP-613 `TypeAlias` assignments in stub files.
|
||||
let previous_deferred_state = self.deferred_state;
|
||||
|
||||
if is_pep_613_type_alias && self.in_stub() {
|
||||
self.deferred_state = DeferredExpressionState::Deferred;
|
||||
}
|
||||
|
||||
// This might be a PEP-613 type alias (`OptionalList: TypeAlias = list[T] | None`). Use
|
||||
// the definition of `OptionalList` as the binding context while inferring the
|
||||
// RHS (`list[T] | None`), in order to bind `T` to `OptionalList`.
|
||||
@@ -5932,8 +5930,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
|
||||
self.typevar_binding_context = previous_typevar_binding_context;
|
||||
|
||||
self.deferred_state = previous_deferred_state;
|
||||
|
||||
self.dataclass_field_specifiers.clear();
|
||||
|
||||
let inferred_ty = if target
|
||||
|
||||
Reference in New Issue
Block a user