[ty] No union with Unknown for module-global symbols
This commit is contained in:
@@ -237,11 +237,11 @@ b: SomeUnknownName = 1 # error: [unresolved-reference]
|
||||
```py
|
||||
from mod import a, b
|
||||
|
||||
reveal_type(a) # revealed: Unknown | Literal[1]
|
||||
reveal_type(a) # revealed: int
|
||||
reveal_type(b) # revealed: Unknown
|
||||
|
||||
# All external modifications of `a` are allowed:
|
||||
a = None
|
||||
a = None # error: [invalid-assignment]
|
||||
```
|
||||
|
||||
### Undeclared and possibly unbound
|
||||
@@ -265,11 +265,11 @@ if flag:
|
||||
# on top of this document.
|
||||
from mod import a, b
|
||||
|
||||
reveal_type(a) # revealed: Unknown | Literal[1]
|
||||
reveal_type(a) # revealed: int
|
||||
reveal_type(b) # revealed: Unknown
|
||||
|
||||
# All external modifications of `a` are allowed:
|
||||
a = None
|
||||
a = None # error: [invalid-assignment]
|
||||
```
|
||||
|
||||
### Undeclared and unbound
|
||||
|
||||
@@ -108,7 +108,7 @@ def foo():
|
||||
global x
|
||||
def bar():
|
||||
# allowed, refers to `x` in the global scope
|
||||
reveal_type(x) # revealed: Unknown | Literal[1]
|
||||
reveal_type(x) # revealed: int
|
||||
bar()
|
||||
del x # allowed, deletes `x` in the global scope (though we don't track that)
|
||||
```
|
||||
|
||||
@@ -25,8 +25,8 @@ reveal_type(y)
|
||||
# error: [possibly-missing-import] "Member `y` of module `maybe_unbound` may be missing"
|
||||
from maybe_unbound import x, y
|
||||
|
||||
reveal_type(x) # revealed: Unknown | Literal[3]
|
||||
reveal_type(y) # revealed: Unknown | Literal[3]
|
||||
reveal_type(x) # revealed: int
|
||||
reveal_type(y) # revealed: int
|
||||
```
|
||||
|
||||
## Maybe unbound annotated
|
||||
@@ -56,7 +56,7 @@ Importing an annotated name prefers the declared type over the inferred type:
|
||||
# error: [possibly-missing-import] "Member `y` of module `maybe_unbound_annotated` may be missing"
|
||||
from maybe_unbound_annotated import x, y
|
||||
|
||||
reveal_type(x) # revealed: Unknown | Literal[3]
|
||||
reveal_type(x) # revealed: int
|
||||
reveal_type(y) # revealed: int
|
||||
```
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ TYPE_CHECKING: bool = ...
|
||||
```py
|
||||
from constants import TYPE_CHECKING
|
||||
|
||||
reveal_type(TYPE_CHECKING) # revealed: Literal[True]
|
||||
reveal_type(TYPE_CHECKING) # revealed: bool
|
||||
|
||||
from stub import TYPE_CHECKING
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class _:
|
||||
[reveal_type(a.z) for _ in range(1)] # revealed: Literal[0]
|
||||
|
||||
def _():
|
||||
reveal_type(a.x) # revealed: Unknown | int | None
|
||||
reveal_type(a.x) # revealed: int | None
|
||||
reveal_type(a.y) # revealed: Unknown | None
|
||||
reveal_type(a.z) # revealed: Unknown | None
|
||||
|
||||
@@ -75,7 +75,7 @@ class _:
|
||||
|
||||
if cond():
|
||||
a = A()
|
||||
reveal_type(a.x) # revealed: int | None | Unknown
|
||||
reveal_type(a.x) # revealed: int | None
|
||||
reveal_type(a.y) # revealed: Unknown | None
|
||||
reveal_type(a.z) # revealed: Unknown | None
|
||||
|
||||
@@ -295,10 +295,10 @@ class C:
|
||||
|
||||
def _():
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(b.a.x[0]) # revealed: Unknown | int | None
|
||||
reveal_type(b.a.x[0]) # revealed: int | None
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(b.a.x) # revealed: Unknown | list[int | None]
|
||||
reveal_type(b.a) # revealed: Unknown | A | None
|
||||
reveal_type(b.a.x) # revealed: list[int | None]
|
||||
reveal_type(b.a) # revealed: A | None
|
||||
```
|
||||
|
||||
## Invalid assignments are not used for narrowing
|
||||
|
||||
@@ -263,7 +263,7 @@ if flag():
|
||||
x = 1
|
||||
|
||||
def f() -> None:
|
||||
reveal_type(x) # revealed: Unknown | Literal[1, 2]
|
||||
reveal_type(x) # revealed: int
|
||||
# Function only used inside this branch
|
||||
f()
|
||||
|
||||
|
||||
@@ -822,7 +822,9 @@ fn place_by_id<'db>(
|
||||
)
|
||||
});
|
||||
|
||||
if scope.file(db).is_stub(db) || scope.scope(db).visibility().is_private() {
|
||||
if scope.node(db).scope_kind().is_module() {
|
||||
inferred.map_type(|ty| ty.promote_literals(db)).into()
|
||||
} else if scope.file(db).is_stub(db) || scope.scope(db).visibility().is_private() {
|
||||
// We generally trust module-level undeclared places in stubs and do not union
|
||||
// with `Unknown`. If we don't do this, simple aliases like `IOError = OSError` in
|
||||
// stubs would result in `IOError` being a union of `OSError` and `Unknown`, which
|
||||
|
||||
@@ -6227,6 +6227,12 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaces any literal types with their corresponding promoted type form (e.g. `Literal["string"]`
|
||||
/// to `str`, or `def _() -> int` to `Callable[[], int]`).
|
||||
pub(crate) fn promote_literals(self, db: &'db dyn Db) -> Type<'db> {
|
||||
self.apply_type_mapping(db, &TypeMapping::PromoteLiterals)
|
||||
}
|
||||
|
||||
/// Locates any legacy `TypeVar`s in this type, and adds them to a set. This is used to build
|
||||
/// up a generic context from any legacy `TypeVar`s that appear in a function parameter list or
|
||||
/// `Generic` specialization.
|
||||
|
||||
Reference in New Issue
Block a user