Skip to content

literals_interactions.py: do not mandate optional narrowing behaviour from type checkers#2209

Merged
carljm merged 1 commit intomainfrom
str-narrowing
Mar 9, 2026
Merged

literals_interactions.py: do not mandate optional narrowing behaviour from type checkers#2209
carljm merged 1 commit intomainfrom
str-narrowing

Conversation

@AlexWaygood
Copy link
Member

@AlexWaygood AlexWaygood commented Mar 7, 2026

X-ref #2208 (comment).

An example in this file mandates that type checkers should narrow an object x of type str to Literal["foo"] after an if x == "foo" check. This example appears to be testing adherence to the passage in the spec at https://typing.python.org/en/latest/spec/literal.html#interactions-with-narrowing. But the passage in the spec here clearly indicates that narrowing str or LiteralString types to Literal strings is optional:

Type checkers may optionally perform additional analysis for both enum and non-enum Literal types beyond what is described in the section above.

For example, it may be useful to perform narrowing based on things like containment or equality checks

The narrowing examples given by the spec are also unsound; it's easy to create a str subclass (and str subclasses are common, due to StrEnum in the standard library) that has custom equality semantics and breaks the assumptions of narrowing like this:

>>> class Foo(str):
...     def __eq__(self, other):
...         return other == "Foo"
... 
>>> Foo("Bar") == "Foo"
True

This PR keeps a version of the existing test (since it comes directly from the spec), but allows type checkers to optionally emit errors on certain lines if they do not implement the optional narrowing behaviour described by the spec. It also adds additional tests using LiteralString, for which narrowing to a Literal string type via equality or containment is unambiguously sound.

The effect of this PR is that mypy and ty now fully pass literals_interactions.py. All other type checkers have their conformance score unchanged.

@AlexWaygood AlexWaygood added the topic: conformance tests Issues with the conformance test suite label Mar 7, 2026
Copy link
Member

@JelleZijlstra JelleZijlstra left a comment

Choose a reason for hiding this comment

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

For usability reasons I think it is more practical to narrow in these cases, but you are technically correct it is unsound.

@davidhalter
Copy link
Contributor

Just wondering: Are you not going to narrow this and other cases? Because it feels like if you don't narrow here you can essentially not narrow in almost any == case due to custom __eq__. But I might just miss something that I'm not thinking about.

@AlexWaygood
Copy link
Member Author

Just wondering: Are you not going to narrow this and other cases? Because it feels like if you don't narrow here you can essentially not narrow in almost any == case due to custom __eq__. But I might just miss something that I'm not thinking about.

That's correct, yeah — we currently do equality narrowing in much more limited circumstances than other type checkers do. You can see exactly what we support here: https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/narrow/conditionals/eq.md

To be clear, we still might change this for reasons of pragmatism! But even if we did change our behaviour here, I still don't think the conformance tests should be mandating behavior that the spec explicitly says is optional.

And while we have had several issues from users surprised about our current behaviour, I wouldn't say there's actually been that much dissatisfaction from users so far about this. Folks have generally agreed with the rationale once it's been explained — the main issue IMO is that the result is not what users initially expect a lot of the time.

@carljm
Copy link
Member

carljm commented Mar 9, 2026

I think the most important thing here is just that the spec says this is optional, and does not generally prescribe narrowing behavior, so the conformance suite shouldn't be requiring it.

@carljm carljm merged commit e6b1896 into main Mar 9, 2026
7 checks passed
@carljm carljm deleted the str-narrowing branch March 9, 2026 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

topic: conformance tests Issues with the conformance test suite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants