diff --git a/crates/red_knot_python_semantic/resources/mdtest/scopes/eager.md b/crates/red_knot_python_semantic/resources/mdtest/scopes/eager.md index 533330ddb7..bfd11b6677 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/scopes/eager.md +++ b/crates/red_knot_python_semantic/resources/mdtest/scopes/eager.md @@ -404,7 +404,7 @@ x = int class C: var: ClassVar[x] -reveal_type(C.var) # revealed: Unknown | str +reveal_type(C.var) # revealed: str x = str ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/subscript/lists.md b/crates/red_knot_python_semantic/resources/mdtest/subscript/lists.md index d074d1b826..192dc4a88e 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/subscript/lists.md +++ b/crates/red_knot_python_semantic/resources/mdtest/subscript/lists.md @@ -12,7 +12,7 @@ x = [1, 2, 3] reveal_type(x) # revealed: list # TODO reveal int -reveal_type(x[0]) # revealed: Unknown +reveal_type(x[0]) # revealed: @Todo(Support for `typing.TypeVar` instances in type expressions) # TODO reveal list reveal_type(x[0:1]) # revealed: @Todo(specialized non-generic class) diff --git a/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_singleton.md b/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_singleton.md index a60efdfd9e..4673affed6 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_singleton.md +++ b/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_singleton.md @@ -128,10 +128,7 @@ python-version = "3.10" import types from knot_extensions import static_assert, is_singleton -# TODO: types.NotImplementedType is a TypeAlias of builtins._NotImplementedType -# Once TypeAlias support is added, it should satisfy `is_singleton` -reveal_type(types.NotImplementedType) # revealed: Unknown | Literal[_NotImplementedType] -static_assert(not is_singleton(types.NotImplementedType)) +static_assert(is_singleton(types.NotImplementedType)) ``` ### Callables diff --git a/crates/red_knot_python_semantic/src/semantic_index/symbol.rs b/crates/red_knot_python_semantic/src/semantic_index/symbol.rs index ec9ef3886e..10f6e9c5d1 100644 --- a/crates/red_knot_python_semantic/src/semantic_index/symbol.rs +++ b/crates/red_knot_python_semantic/src/semantic_index/symbol.rs @@ -115,6 +115,10 @@ impl<'db> ScopeId<'db> { self.node(db).scope_kind().is_function_like() } + pub(crate) fn is_module_scope(self, db: &'db dyn Db) -> bool { + self.node(db).scope_kind().is_module() + } + pub(crate) fn is_type_parameter(self, db: &'db dyn Db) -> bool { self.node(db).scope_kind().is_type_parameter() } @@ -263,6 +267,10 @@ impl ScopeKind { matches!(self, ScopeKind::Class) } + pub(crate) fn is_module(self) -> bool { + matches!(self, ScopeKind::Module) + } + pub(crate) fn is_type_parameter(self) -> bool { matches!(self, ScopeKind::Annotation | ScopeKind::TypeAlias) } diff --git a/crates/red_knot_python_semantic/src/symbol.rs b/crates/red_knot_python_semantic/src/symbol.rs index dae79c3b63..4e713a7fde 100644 --- a/crates/red_knot_python_semantic/src/symbol.rs +++ b/crates/red_knot_python_semantic/src/symbol.rs @@ -593,8 +593,18 @@ fn symbol_by_id<'db>( "__slots__" | "TYPE_CHECKING" ); - widen_type_for_undeclared_public_symbol(db, inferred, is_considered_non_modifiable) - .into() + if scope.is_module_scope(db) && scope.file(db).is_stub(db.upcast()) { + // We generally trust module-level undeclared symbols 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 + // leads to all sorts of downstream problems. Similarly, type variables are often + // defined as `_T = TypeVar("_T")`, without being declared. + + inferred.into() + } else { + widen_type_for_undeclared_public_symbol(db, inferred, is_considered_non_modifiable) + .into() + } } // Symbol has conflicting declared types Err((declared, _)) => { diff --git a/crates/red_knot_python_semantic/src/types/signatures.rs b/crates/red_knot_python_semantic/src/types/signatures.rs index 52b1ab827f..c74554fe91 100644 --- a/crates/red_knot_python_semantic/src/types/signatures.rs +++ b/crates/red_knot_python_semantic/src/types/signatures.rs @@ -1631,10 +1631,7 @@ mod tests { assert_eq!(a_name, "a"); assert_eq!(b_name, "b"); // Parameter resolution deferred; we should see B - assert_eq!( - a_annotated_ty.unwrap().display(&db).to_string(), - "Unknown | B" - ); + assert_eq!(a_annotated_ty.unwrap().display(&db).to_string(), "B"); assert_eq!(b_annotated_ty.unwrap().display(&db).to_string(), "T"); }