Conversation
|
ba56f82 to
839f7a4
Compare
839f7a4 to
4ac0df3
Compare
* main: [`airflow`] Add fix to remove deprecated keyword arguments (`AIR302`) (#14887) Improve mdtests style (#14884) Reference `suppress-dummy-regex-options` in documentation of rules supporting it (#14888) [`flake8-bugbear`] `itertools.batched()` without explicit `strict` (`B911`) (#14408) [`ruff`] Mark autofix for `RUF052` as always unsafe (#14824) [red-knot] Improve type inference for except handlers (#14838) More typos found by codespell (#14880) [red-knot] move standalone expression_ty to TypeInferenceBuilder::file_expression_ty (#14879) [`ruff`] Do not simplify `round()` calls (`RUF046`) (#14832) Stop referring to early ruff versions (#14862) Fix a typo in `class.rs` (#14877) [`flake8-pyi`] Also remove `self` and `cls`'s annotation (`PYI034`) (#14801) [`pyupgrade`] Remove unreachable code in `UP015` implementation (#14871) [`flake8-bugbear`] Skip `B028` if `warnings.warn` is called with `*args` or `**kwargs` (#14870)
dcreager
left a comment
There was a problem hiding this comment.
(Initial responses, still need to make the type ⇒ type[object] change and add the equivalent_to tests)
| (Type::Unknown | Type::Any | Type::Todo(_), _) => false, | ||
| (_, Type::Unknown | Type::Any | Type::Todo(_)) => false, |
There was a problem hiding this comment.
I removed these since they (and the new Subclass(Any) form) are handled by the is_fully_static checks above.
| | Type::SliceLiteral(_) | ||
| | Type::KnownInstance(_) => true, | ||
| Type::ClassLiteral(_) | Type::SubclassOf(_) | Type::Instance(_) => { | ||
| Type::SubclassOf(SubclassOfType { base }) => matches!(base, ClassBase::Class(_)), |
There was a problem hiding this comment.
SubclassOf(Any) is not fully static
There was a problem hiding this comment.
Looking good! In addition to the additional unit tests I mentioned inline, this PR seems a good candidate to run the quickcheck property-based tests for core type algebra invariants. These don't run in CI because they are slow, but it would be good to see whether they catch any issues here. See https://github.com/astral-sh/ruff/blob/main/crates/red_knot_python_semantic/src/types/property_tests.rs
EDIT: just realized that in order to get value from that on this PR, we should also add SubclassOf types to the arbitrary_core_type function there!
| ( | ||
| Type::Instance(InstanceType { class: self_class }), | ||
| Type::Instance(InstanceType { | ||
| class: target_class, | ||
| }), | ||
| ) if { | ||
| let self_known = self_class.known(db); | ||
| matches!( | ||
| self_known, | ||
| Some(KnownClass::NoneType | KnownClass::NoDefaultType) | ||
| ) && self_known == target_class.known(db) | ||
| } => | ||
| { | ||
| true | ||
| } |
There was a problem hiding this comment.
this gets a little hard to read 😄 how about writing it like this?
| ( | |
| Type::Instance(InstanceType { class: self_class }), | |
| Type::Instance(InstanceType { | |
| class: target_class, | |
| }), | |
| ) if { | |
| let self_known = self_class.known(db); | |
| matches!( | |
| self_known, | |
| Some(KnownClass::NoneType | KnownClass::NoDefaultType) | |
| ) && self_known == target_class.known(db) | |
| } => | |
| { | |
| true | |
| } | |
| (Type::Instance(self_instance), Type::Instance(target_instance)) => { | |
| let Some(self_known_class) = self_instance.class.known(db) else { | |
| return false; | |
| }; | |
| if !matches!( | |
| self_known_class, | |
| KnownClass::NoneType | KnownClass::NoDefaultType | |
| ) { | |
| return false; | |
| } | |
| Some(self_known_class) == target_instance.class.known(db) | |
| } |
There was a problem hiding this comment.
We have to be careful here; these return false in the suggested change are not correct. They would have to be return self == other, and I'm not sure we want to duplicate that condition in various places.
There was a problem hiding this comment.
I had also considered handling each of the special cases with a separate if statement + early return. Then it would possibly be clearer that self == other is the fall-back / general case. But we had other large match blocks elsewhere that made me think that might be preferred house style. I will take a stab at the early return pattern and see if it's more readable.
There was a problem hiding this comment.
I will take a stab at the early return pattern and see if it's more readable.
Now using early return. lmkwyt
| ) if object_class.is_known(db, KnownClass::Object) | ||
| && type_class.is_known(db, KnownClass::Type) => | ||
| { | ||
| true | ||
| } |
There was a problem hiding this comment.
| ) if object_class.is_known(db, KnownClass::Object) | |
| && type_class.is_known(db, KnownClass::Type) => | |
| { | |
| true | |
| } | |
| ) => { | |
| object_class.is_known(db, KnownClass::Object) | |
| && type_class.is_known(db, KnownClass::Type) | |
| } |
There was a problem hiding this comment.
This one should be safe because a Type::Instance can't be == to a Type::SubclassOf.
I already did this. I didn't mention it here because they are currently broken (surprise!). I'll put up a small PR with a fix. Edit: #14897 |
There was a problem hiding this comment.
Thank you for all the updates and the new tests!
FWIW, I did successfully run the property tests on your branch after cherry-picking my fix in #14897 and applying the following patch, where the 4=>3 change is a weird way to suppress the creation of intersection types to prevent running into #14899:
diff --git a/crates/red_knot_python_semantic/src/types/property_tests.rs b/crates/red_knot_python_semantic/src/types/property_tests.rs
index 15f4d5648..e6b223034 100644
--- a/crates/red_knot_python_semantic/src/types/property_tests.rs
+++ b/crates/red_knot_python_semantic/src/types/property_tests.rs
@@ -64,6 +64,10 @@ fn arbitrary_core_type(g: &mut Gen) -> Ty {
Ty::BuiltinClassLiteral("int"),
Ty::BuiltinClassLiteral("bool"),
Ty::BuiltinClassLiteral("object"),
+ Ty::SubclassOfAny,
+ Ty::SubclassOfBuiltinClass("object"),
+ Ty::SubclassOfBuiltinClass("int"),
+ Ty::SubclassOfBuiltinClass("bool"),
])
.unwrap()
.clone()
@@ -78,7 +82,7 @@ fn arbitrary_type(g: &mut Gen, size: u32) -> Ty {
if size == 0 {
arbitrary_core_type(g)
} else {
- match u32::arbitrary(g) % 4 {
+ match u32::arbitrary(g) % 3 {
0 => arbitrary_core_type(g),
1 => Ty::Union(
(0..*g.choose(&[2, 3]).unwrap())
This adds support for
type[Any], which represents an unknown type (not an instance of an unknown type), andtype, which we are choosing to interpret astype[object].Closes #14546