Skip to content

Comments

[red-knot] Fix more edge cases for intersection simplification with LiteralString and AlwaysTruthy/AlwaysFalsy#15496

Merged
AlexWaygood merged 1 commit intomainfrom
alex/more-intersections
Jan 15, 2025
Merged

[red-knot] Fix more edge cases for intersection simplification with LiteralString and AlwaysTruthy/AlwaysFalsy#15496
AlexWaygood merged 1 commit intomainfrom
alex/more-intersections

Conversation

@AlexWaygood
Copy link
Member

@AlexWaygood AlexWaygood commented Jan 15, 2025

Summary

Re-reading the diff in bcf0a71, I realised that there were still one or two cases I failed to handle properly. Namely, we currently simplify LiteralString & AlwaysTruthy to LiteralString & ~Literal[""], but we do not do the same simplification for AlwaysTruthy & LiteralString. Similarly, we currently simplify LiteralString & ~AlwaysFalsy to LiteralString & ~Literal[""], but we don't do the same for ~AlwaysFalsy & LiteralString.

This PR fixes those cases, and moves all LiteralString handling to the top of the add_positive() method so that it's easier to think through the various cases and see that they're both complete and correct. The default diff that GitHub shows is a bit messy because the refactoring to add_positive means that the indentation increases by one level for most of the function. Everything is much easier to review if you select GitHub's option to view the diff without whitespace changes, however.

Test Plan

  • cargo test -p red_knot_python_semantic
  • QUICKCHECK_TESTS=200000 cargo test --release -p red_knot_python_semantic -- --ignored types::property_tests::stable
  • uvx pre-commit run -a

@AlexWaygood AlexWaygood added the ty Multi-file analysis & type inference label Jan 15, 2025
@AlexWaygood AlexWaygood marked this pull request as draft January 15, 2025 13:44
@AlexWaygood AlexWaygood force-pushed the alex/more-intersections branch from c7d4465 to 1408876 Compare January 15, 2025 13:48
@AlexWaygood AlexWaygood marked this pull request as ready for review January 15, 2025 13:48
@AlexWaygood
Copy link
Member Author

Briefly deleted my whole patch there by accident 😅 it's back now

@AlexWaygood
Copy link
Member Author

AlexWaygood commented Jan 15, 2025

Once we understand differently ordered intersections as equivalent to each other (which I'm working on), we'll be able to add a property test that would have caught this. I've noted it down as a TODO for myself.

@AlexWaygood
Copy link
Member Author

No change on the codspeed benchmarks

@github-actions
Copy link
Contributor

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

Comment on lines +259 to +276
// `AlwaysTruthy & LiteralString` -> `LiteralString & ~Literal[""]`
Type::LiteralString if self.positive.swap_remove(&Type::AlwaysTruthy) => {
self.add_positive(db, Type::LiteralString);
self.add_negative(db, Type::string_literal(db, ""));
}
// `AlwaysFalsy & LiteralString` -> `Literal[""]`
Type::LiteralString if self.positive.swap_remove(&Type::AlwaysFalsy) => {
self.add_positive(db, Type::string_literal(db, ""));
}
// `LiteralString & ~AlwaysTruthy` -> `LiteralString & AlwaysFalsy` -> `Literal[""]`
Type::LiteralString if self.negative.swap_remove(&Type::AlwaysTruthy) => {
self.add_positive(db, Type::string_literal(db, ""));
}
// `LiteralString & ~AlwaysFalsy` -> `LiteralString & ~Literal[""]`
Type::LiteralString if self.negative.swap_remove(&Type::AlwaysFalsy) => {
self.add_positive(db, Type::LiteralString);
self.add_negative(db, Type::string_literal(db, ""));
}
Copy link
Member Author

Choose a reason for hiding this comment

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

it's tempting to think that we could avoid some indirection here, e.g.

Suggested change
// `AlwaysTruthy & LiteralString` -> `LiteralString & ~Literal[""]`
Type::LiteralString if self.positive.swap_remove(&Type::AlwaysTruthy) => {
self.add_positive(db, Type::LiteralString);
self.add_negative(db, Type::string_literal(db, ""));
}
// `AlwaysFalsy & LiteralString` -> `Literal[""]`
Type::LiteralString if self.positive.swap_remove(&Type::AlwaysFalsy) => {
self.add_positive(db, Type::string_literal(db, ""));
}
// `LiteralString & ~AlwaysTruthy` -> `LiteralString & AlwaysFalsy` -> `Literal[""]`
Type::LiteralString if self.negative.swap_remove(&Type::AlwaysTruthy) => {
self.add_positive(db, Type::string_literal(db, ""));
}
// `LiteralString & ~AlwaysFalsy` -> `LiteralString & ~Literal[""]`
Type::LiteralString if self.negative.swap_remove(&Type::AlwaysFalsy) => {
self.add_positive(db, Type::LiteralString);
self.add_negative(db, Type::string_literal(db, ""));
}
// `AlwaysTruthy & LiteralString` -> `LiteralString & ~Literal[""]`
Type::LiteralString if self.positive.swap_remove(&Type::AlwaysTruthy) => {
self.positive.insert(Type::LiteralString);
self.negative.insert(Type::string_literal(db, ""));
}
// `AlwaysFalsy & LiteralString` -> `Literal[""]`
Type::LiteralString if self.positive.swap_remove(&Type::AlwaysFalsy) => {
self.positive.insert(Type::string_literal(db, ""));
}
// `LiteralString & ~AlwaysTruthy` -> `LiteralString & AlwaysFalsy` -> `Literal[""]`
Type::LiteralString if self.negative.swap_remove(&Type::AlwaysTruthy) => {
self.positive.insert(Type::string_literal(db, ""));
}
// `LiteralString & ~AlwaysFalsy` -> `LiteralString & ~Literal[""]`
Type::LiteralString if self.negative.swap_remove(&Type::AlwaysFalsy) => {
self.positive.insert(Type::LiteralString);
self.negative.insert(Type::string_literal(db, ""));
}

but this causes many property test failures, because we skip the simplifications done in the fallback branch of this function where redundant supertypes are removed if subtypes exist in the intersection, and where the entire intersection simplifies to Never if it contains a pair of disjoint types.

Copy link
Contributor

@sharkdp sharkdp left a comment

Choose a reason for hiding this comment

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

Thank you!

@AlexWaygood AlexWaygood merged commit 55a7f72 into main Jan 15, 2025
21 checks passed
@AlexWaygood AlexWaygood deleted the alex/more-intersections branch January 15, 2025 15:02
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.

2 participants