Skip to content

Conversation

@AlexWaygood
Copy link
Member

@AlexWaygood AlexWaygood commented Dec 11, 2024

Summary

There's a functional change here, and a few cosmetic changes.

The functional change is that we currently consider Literal[str] to be disjoint from type[Any]. But they're not disjoint: Any here could be materialized as str or object; in those materializations, the two types would clearly overlap, and therefore type[Any] overlaps with Literal[str]. This PR fixes our logic in Type::is_disjoint_from to reflect that.

Also included in this PR are cosmetic changes to Type::is_subtype_of. The main reason for these changes is that currently we have Type::SubclassOf(target_class)) branches in match statements where the target_class variable actually has type ClassBase rather than Class; this is quite confusing. A secondary reason for these changes is that it should be impossible for us to encounter Type::SubclassOf(SubclassOfType { base }) instances in this match statement where base is not a ClassBase::Class() variant, since all other ClassBase::Class() variants are not fully static exit, and therefore we immediately early in is_subtype_of() here if we encounter one of them:

pub(crate) fn is_subtype_of(self, db: &'db dyn Db, target: Type<'db>) -> bool {
if self.is_equivalent_to(db, target) {
return true;
}
if !self.is_fully_static(db) || !target.is_fully_static(db) {
return false;

The changes to Type::is_subtype_of() clarify that we shouldn't be dealing with any other ClassBase::Class() variants in this match statement; we should therefore be using Class::is_subclass_of() rather than Class:is_subclass_of_base().

As a result of the above changes, Class::is_subclass_of_base() actually becomes unused, so this PR removes it as well. I think this is probably also for the best: a ClassBase and a Class are two different things, and it feels like it blurs the two concepts to have a method that asks whether a class is a "subclass of" a ClassBase. If we need to ask this question again in the future, it's not that much more verbose to just do class.mro(db).contains(&base).

Test Plan

cargo test -p red_knot_python_semantic. The new test case for the is_not_disjoint_from test is the only one added in this PR that fails on main, but the other added test cases seem useful anyway.

@AlexWaygood AlexWaygood added the ty Multi-file analysis & type inference label Dec 11, 2024
@AlexWaygood AlexWaygood force-pushed the alex/type-t-edge-cases branch from a15423a to 0db080d Compare December 11, 2024 14:24
@github-actions
Copy link
Contributor

github-actions bot commented Dec 11, 2024

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

Copy link
Contributor

@carljm carljm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I think I do prefer always explicitly unpacking to a Class, and avoiding methods that blur the line between a ClassBase and a Class.

@AlexWaygood
Copy link
Member Author

Okay... I tried to add some more comments to the function... and ended up writing #14924... which I will have to finish tomorrow...

@AlexWaygood
Copy link
Member Author

I think tomorrow I'll rip out the is_subtype_of parts of this so it only deals with is_disjoint_from. And I'll continue work on #14924, which deals with the is_subtype_of questions in a more comprehensive way.

@carljm
Copy link
Contributor

carljm commented Dec 11, 2024

I think tomorrow I'll rip out the is_subtype_of parts of this so it only deals with is_disjoint_from. And I'll continue work on #14924, which deals with the is_subtype_of questions in a more comprehensive way.

Sounds fine, though I also think it would be fine if this PR at least removes the is_subtype_of case that we know is wrong and doesn't fail any tests if removed, since we've established that much here. Just makes the follow up PR on is_subtype_of that much easier to review.

@AlexWaygood
Copy link
Member Author

Sure

@AlexWaygood AlexWaygood changed the title [red-knot] Fixup a few edge cases regarding type[Any] [red-knot] Fixup a few edge cases regarding type[] Dec 12, 2024
@AlexWaygood AlexWaygood force-pushed the alex/type-t-edge-cases branch from db08069 to ee540c7 Compare December 12, 2024 14:30
@AlexWaygood AlexWaygood requested a review from carljm December 12, 2024 14:32
Copy link
Contributor

@carljm carljm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

Comment on lines +3056 to +3059
Intersection {
pos: Vec<Ty>,
neg: Vec<Ty>,
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor nit, but it doesn't seem necessary to explode this onto multiple lines? Is rustfmt doing that because the trailing comma was added?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no idea why rustfmt is doing it! I can see if I can get rustfmt to undo it

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot get rustfmt to undo it. Ours not to reason why?

@AlexWaygood AlexWaygood merged commit 5893090 into main Dec 12, 2024
21 checks passed
@AlexWaygood AlexWaygood deleted the alex/type-t-edge-cases branch December 12, 2024 16:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants