Skip to content

Commit abc5605

Browse files
committed
address review
1 parent 662dbb5 commit abc5605

File tree

5 files changed

+78
-38
lines changed

5 files changed

+78
-38
lines changed

crates/red_knot_project/tests/check.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
use anyhow::{anyhow, Context};
22
use red_knot_project::{ProjectDatabase, ProjectMetadata};
3-
use red_knot_python_semantic::{HasType, SemanticModel};
3+
use red_knot_python_semantic::{HasType, Program, SemanticModel};
44
use ruff_db::files::{system_path_to_file, File};
55
use ruff_db::parsed::parsed_module;
66
use ruff_db::system::{SystemPath, SystemPathBuf, TestSystem};
77
use ruff_python_ast::visitor::source_order;
88
use ruff_python_ast::visitor::source_order::SourceOrderVisitor;
9-
use ruff_python_ast::{self as ast, Alias, Expr, Parameter, ParameterWithDefault, Stmt};
9+
use ruff_python_ast::{
10+
self as ast, Alias, Expr, Parameter, ParameterWithDefault, PythonVersion, Stmt,
11+
};
12+
use salsa::Setter;
1013

1114
fn setup_db(project_root: &SystemPath, system: TestSystem) -> anyhow::Result<ProjectDatabase> {
1215
let project = ProjectMetadata::discover(project_root, &system)?;
@@ -84,6 +87,10 @@ fn run_corpus_tests(pattern: &str) -> anyhow::Result<()> {
8487

8588
let mut db = setup_db(&root, system.clone())?;
8689

90+
Program::get(&db)
91+
.set_python_version(&mut db)
92+
.to(PythonVersion::latest());
93+
8794
let workspace_root = get_cargo_workspace_root()?;
8895
let workspace_root = workspace_root.to_string();
8996

crates/red_knot_python_semantic/resources/mdtest/import/builtins.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,18 @@ typeshed = "/typeshed"
3232
`/typeshed/stdlib/builtins.pyi`:
3333

3434
```pyi
35+
class object: ...
3536
class Custom: ...
3637

3738
custom_builtin: Custom
3839
```
3940

41+
`/typeshed/stdlib/types.pyi`:
42+
43+
```pyi
44+
class ModuleType: ...
45+
```
46+
4047
`/typeshed/stdlib/typing_extensions.pyi`:
4148

4249
```pyi
@@ -67,6 +74,12 @@ foo = bar
6774
bar = 1
6875
```
6976

77+
`/typeshed/stdlib/types.pyi`:
78+
79+
```pyi
80+
class ModuleType: ...
81+
```
82+
7083
`/typeshed/stdlib/typing_extensions.pyi`:
7184

7285
```pyi

crates/red_knot_python_semantic/resources/mdtest/mdtest_custom_typeshed.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,21 @@ We can then place custom stub files in `/typeshed/stdlib`, for example:
2222
`/typeshed/stdlib/builtins.pyi`:
2323

2424
```pyi
25+
class object: ...
26+
class type: ...
27+
class ellipsis: ...
28+
2529
class BuiltinClass: ...
2630

2731
builtin_symbol: BuiltinClass
2832
```
2933

34+
`/typeshed/stdlib/types.pyi`:
35+
36+
```pyi
37+
class ModuleType: ...
38+
```
39+
3040
`/typeshed/stdlib/sys/__init__.pyi`:
3141

3242
```pyi
@@ -70,11 +80,18 @@ class OldClass: ...
7080
class NewClass: ...
7181
```
7282

83+
`/typeshed/stdlib/types.pyi`:
84+
85+
```pyi
86+
class ModuleType: ...
87+
```
88+
7389
`/typeshed/stdlib/VERSIONS`:
7490

7591
```text
7692
old_module: 3.0-
7793
new_module: 3.11-
94+
types: 3.9-
7895
```
7996

8097
```py
@@ -102,6 +119,12 @@ typeshed = "/typeshed"
102119
def reveal_type(obj, /): ...
103120
```
104121

122+
`/typeshed/stdlib/types.pyi`:
123+
124+
```pyi
125+
class ModuleType: ...
126+
```
127+
105128
```py
106129
reveal_type(()) # revealed: tuple[()]
107130
```

crates/red_knot_python_semantic/src/types.rs

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -730,10 +730,9 @@ impl<'db> Type<'db> {
730730
// `Literal[str]` is a subtype of `type` because the `str` class object is an instance of its metaclass `type`.
731731
// `Literal[abc.ABC]` is a subtype of `abc.ABCMeta` because the `abc.ABC` class object
732732
// is an instance of its metaclass `abc.ABCMeta`.
733-
(Type::ClassLiteral(ClassLiteralType { class }), _) => class
734-
.metaclass(db)
735-
.to_instance(db)
736-
.is_some_and(|instance_type| instance_type.is_subtype_of(db, target)),
733+
(Type::ClassLiteral(ClassLiteralType { class }), _) => {
734+
class.metaclass_instance_type(db).is_subtype_of(db, target)
735+
}
737736

738737
// `type[str]` (== `SubclassOf("str")` in red-knot) describes all possible runtime subclasses
739738
// of the class object `str`. It is a subtype of `type` (== `Instance("type")`) because `str`
@@ -745,7 +744,7 @@ impl<'db> Type<'db> {
745744
(Type::SubclassOf(subclass_of_ty), _) => subclass_of_ty
746745
.subclass_of()
747746
.into_class()
748-
.and_then(|class| class.metaclass(db).to_instance(db))
747+
.map(|class| class.metaclass_instance_type(db))
749748
.is_some_and(|metaclass_instance_type| {
750749
metaclass_instance_type.is_subtype_of(db, target)
751750
}),
@@ -1105,14 +1104,9 @@ impl<'db> Type<'db> {
11051104
ClassBase::Dynamic(_) => {
11061105
KnownClass::Type.to_instance(db).is_disjoint_from(db, other)
11071106
}
1108-
ClassBase::Class(class) => {
1109-
class
1110-
.metaclass(db)
1111-
.to_instance(db)
1112-
.is_some_and(|metaclass_instance_type| {
1113-
metaclass_instance_type.is_disjoint_from(db, other)
1114-
})
1115-
}
1107+
ClassBase::Class(class) => class
1108+
.metaclass_instance_type(db)
1109+
.is_disjoint_from(db, other),
11161110
},
11171111

11181112
(Type::KnownInstance(known_instance), Type::Instance(InstanceType { class }))
@@ -1182,11 +1176,8 @@ impl<'db> Type<'db> {
11821176
(Type::ClassLiteral(ClassLiteralType { class }), instance @ Type::Instance(_))
11831177
| (instance @ Type::Instance(_), Type::ClassLiteral(ClassLiteralType { class })) => {
11841178
!class
1185-
.metaclass(db)
1186-
.to_instance(db)
1187-
.is_some_and(|metaclass_instance_type| {
1188-
metaclass_instance_type.is_subtype_of(db, instance)
1189-
})
1179+
.metaclass_instance_type(db)
1180+
.is_subtype_of(db, instance)
11901181
}
11911182

11921183
(Type::FunctionLiteral(..), Type::Instance(InstanceType { class }))
@@ -2090,13 +2081,9 @@ impl<'db> Type<'db> {
20902081
Type::FunctionLiteral(_) => Truthiness::AlwaysTrue,
20912082
Type::Callable(_) => Truthiness::AlwaysTrue,
20922083
Type::ModuleLiteral(_) => Truthiness::AlwaysTrue,
2093-
Type::ClassLiteral(ClassLiteralType { class }) => {
2094-
if let Some(metaclass_instance_type) = class.metaclass(db).to_instance(db) {
2095-
metaclass_instance_type.try_bool_impl(db, allow_short_circuit)?
2096-
} else {
2097-
Truthiness::Ambiguous
2098-
}
2099-
}
2084+
Type::ClassLiteral(ClassLiteralType { class }) => class
2085+
.metaclass_instance_type(db)
2086+
.try_bool_impl(db, allow_short_circuit)?,
21002087
Type::SubclassOf(subclass_of_ty) => match subclass_of_ty.subclass_of() {
21012088
ClassBase::Dynamic(_) => Truthiness::Ambiguous,
21022089
ClassBase::Class(class) => {
@@ -2936,8 +2923,6 @@ impl<'db> Type<'db> {
29362923
Some(builder.build())
29372924
}
29382925
Type::Intersection(_) => Some(todo_type!("Type::Intersection.to_instance()")),
2939-
// TODO: calling `.to_instance()` on any of these should result in a diagnostic,
2940-
// since they already indicate that the object is an instance of some kind:
29412926
Type::BooleanLiteral(_)
29422927
| Type::BytesLiteral(_)
29432928
| Type::FunctionLiteral(_)

crates/red_knot_python_semantic/src/types/class.rs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,14 @@ impl<'db> Class<'db> {
188188
.unwrap_or_else(|_| SubclassOfType::subclass_of_unknown())
189189
}
190190

191+
/// Return a type representing "the set of all instances of the metaclass of this class".
192+
pub(super) fn metaclass_instance_type(self, db: &'db dyn Db) -> Type<'db> {
193+
self
194+
.metaclass(db)
195+
.to_instance(db)
196+
.expect("`Type::to_instance()` should always return `Some()` when called on the type of a metaclass")
197+
}
198+
191199
/// Return the metaclass of this class, or an error if the metaclass cannot be inferred.
192200
#[salsa::tracked]
193201
pub(super) fn try_metaclass(self, db: &'db dyn Db) -> Result<Type<'db>, MetaclassError<'db>> {
@@ -972,16 +980,20 @@ impl<'db> KnownClass {
972980
self.try_to_class_literal(db)
973981
.map(Type::ClassLiteral)
974982
.unwrap_or_else(|lookup_error| {
975-
if cfg!(test) {
976-
panic!("{}", lookup_error.display(db, self));
977-
} else if MESSAGES.lock().unwrap().insert(self) {
983+
assert!(
984+
!cfg!(any(test, debug_assertions)),
985+
"{}",
986+
lookup_error.display(db, self)
987+
);
988+
989+
if MESSAGES.lock().unwrap().insert(self) {
978990
if matches!(
979991
lookup_error,
980992
KnownClassLookupError::ClassPossiblyUnbound { .. }
981993
) {
982-
tracing::warn!("{}", lookup_error.display(db, self));
994+
tracing::debug!("{}", lookup_error.display(db, self));
983995
} else {
984-
tracing::warn!(
996+
tracing::debug!(
985997
"{}. Falling back to `Unknown` for the symbol instead.",
986998
lookup_error.display(db, self)
987999
);
@@ -1717,7 +1729,7 @@ mod tests {
17171729
}
17181730
}
17191731

1720-
fn setup_db_with_broken_typeshed(builtins_file: &str) -> TestDb {
1732+
fn setup_db_with_minimal_typeshed(builtins_file: &str) -> TestDb {
17211733
TestDbBuilder::new()
17221734
.with_custom_typeshed("/typeshed")
17231735
.with_file("/typeshed/stdlib/builtins.pyi", builtins_file)
@@ -1730,21 +1742,21 @@ mod tests {
17301742
#[test]
17311743
#[should_panic(expected = "Could not find class `builtins.int` in typeshed")]
17321744
fn known_class_to_class_literal_panics_with_test_feature_enabled() {
1733-
let db = setup_db_with_broken_typeshed("class object: ...");
1745+
let db = setup_db_with_minimal_typeshed("class object: ...");
17341746
KnownClass::Int.to_class_literal(&db);
17351747
}
17361748

17371749
#[test]
17381750
#[should_panic(expected = "Could not find class `builtins.int` in typeshed")]
17391751
fn known_class_to_instance_panics_with_test_feature_enabled() {
1740-
let db = setup_db_with_broken_typeshed("class object: ...");
1752+
let db = setup_db_with_minimal_typeshed("class object: ...");
17411753
KnownClass::Int.to_instance(&db);
17421754
}
17431755

17441756
#[test]
17451757
#[should_panic(expected = "found a symbol of type `Unknown | Literal[42]` instead")]
17461758
fn known_class_to_subclass_of_panics_with_test_feature_enabled() {
1747-
let db = setup_db_with_broken_typeshed("int = 42");
1759+
let db = setup_db_with_minimal_typeshed("int = 42");
17481760
KnownClass::Int.to_subclass_of(&db);
17491761
}
17501762
}

0 commit comments

Comments
 (0)