diff --git a/conformance/results/mypy/literals_interactions.toml b/conformance/results/mypy/literals_interactions.toml
index c7b83588..a9f03f04 100644
--- a/conformance/results/mypy/literals_interactions.toml
+++ b/conformance/results/mypy/literals_interactions.toml
@@ -1,17 +1,20 @@
-conformant = "Partial"
notes = """
-Does not narrow type of `x` with `x in Literal` type guard pattern.
+Does not narrow `str` or `LiteralString` types to `Literal` string types via equality or containment checks.
"""
output = """
+literals_interactions.py:14: error: Tuple index out of range [misc]
literals_interactions.py:15: error: Tuple index out of range [misc]
literals_interactions.py:16: error: Tuple index out of range [misc]
literals_interactions.py:17: error: Tuple index out of range [misc]
-literals_interactions.py:18: error: Tuple index out of range [misc]
-literals_interactions.py:106: error: Argument 1 to "expects_bad_status" has incompatible type "str"; expected "Literal['MALFORMED', 'ABORTED']" [arg-type]
-literals_interactions.py:109: error: Argument 1 to "expects_pending_status" has incompatible type "str"; expected "Literal['PENDING']" [arg-type]
+literals_interactions.py:111: error: Argument 1 to "expects_bad_status" has incompatible type "str"; expected "Literal['MALFORMED', 'ABORTED']" [arg-type]
+literals_interactions.py:113: error: Argument 1 to "expects_bad_status" has incompatible type "str"; expected "Literal['MALFORMED', 'ABORTED']" [arg-type]
+literals_interactions.py:116: error: Argument 1 to "expects_bad_status" has incompatible type "str"; expected "Literal['MALFORMED', 'ABORTED']" [arg-type]
+literals_interactions.py:119: error: Argument 1 to "expects_pending_status" has incompatible type "str"; expected "Literal['PENDING']" [arg-type]
+literals_interactions.py:128: error: Argument 1 to "expects_bad_status" has incompatible type "str"; expected "Literal['MALFORMED', 'ABORTED']" [arg-type]
+literals_interactions.py:130: error: Argument 1 to "expects_bad_status" has incompatible type "str"; expected "Literal['MALFORMED', 'ABORTED']" [arg-type]
+literals_interactions.py:133: error: Argument 1 to "expects_bad_status" has incompatible type "str"; expected "Literal['MALFORMED', 'ABORTED']" [arg-type]
+literals_interactions.py:136: error: Argument 1 to "expects_pending_status" has incompatible type "str"; expected "Literal['PENDING']" [arg-type]
"""
-conformance_automated = "Fail"
+conformance_automated = "Pass"
errors_diff = """
-Line 106: Unexpected errors ['literals_interactions.py:106: error: Argument 1 to "expects_bad_status" has incompatible type "str"; expected "Literal[\\'MALFORMED\\', \\'ABORTED\\']" [arg-type]']
-Line 109: Unexpected errors ['literals_interactions.py:109: error: Argument 1 to "expects_pending_status" has incompatible type "str"; expected "Literal[\\'PENDING\\']" [arg-type]']
"""
diff --git a/conformance/results/pyrefly/literals_interactions.toml b/conformance/results/pyrefly/literals_interactions.toml
index 881854c8..451fa2d4 100644
--- a/conformance/results/pyrefly/literals_interactions.toml
+++ b/conformance/results/pyrefly/literals_interactions.toml
@@ -3,8 +3,8 @@ conformance_automated = "Pass"
errors_diff = """
"""
output = """
-ERROR literals_interactions.py:15:7-8: Index 5 out of range for tuple with 3 elements [bad-index]
-ERROR literals_interactions.py:16:7-8: Index -5 out of range for tuple with 3 elements [bad-index]
-ERROR literals_interactions.py:17:7-8: Index 4 out of range for tuple with 3 elements [bad-index]
-ERROR literals_interactions.py:18:7-9: Index -4 out of range for tuple with 3 elements [bad-index]
+ERROR literals_interactions.py:14:7-8: Index 5 out of range for tuple with 3 elements [bad-index]
+ERROR literals_interactions.py:15:7-8: Index -5 out of range for tuple with 3 elements [bad-index]
+ERROR literals_interactions.py:16:7-8: Index 4 out of range for tuple with 3 elements [bad-index]
+ERROR literals_interactions.py:17:7-9: Index -4 out of range for tuple with 3 elements [bad-index]
"""
diff --git a/conformance/results/pyright/literals_interactions.toml b/conformance/results/pyright/literals_interactions.toml
index cd51f439..1ecbc1f0 100644
--- a/conformance/results/pyright/literals_interactions.toml
+++ b/conformance/results/pyright/literals_interactions.toml
@@ -1,9 +1,9 @@
conformant = "Pass"
output = """
-literals_interactions.py:15:5 - error: Index 5 is out of range for type tuple[int, str, list[bool]] (reportGeneralTypeIssues)
-literals_interactions.py:16:5 - error: Index -5 is out of range for type tuple[int, str, list[bool]] (reportGeneralTypeIssues)
-literals_interactions.py:17:5 - error: Index 4 is out of range for type tuple[int, str, list[bool]] (reportGeneralTypeIssues)
-literals_interactions.py:18:5 - error: Index -4 is out of range for type tuple[int, str, list[bool]] (reportGeneralTypeIssues)
+literals_interactions.py:14:5 - error: Index 5 is out of range for type tuple[int, str, list[bool]] (reportGeneralTypeIssues)
+literals_interactions.py:15:5 - error: Index -5 is out of range for type tuple[int, str, list[bool]] (reportGeneralTypeIssues)
+literals_interactions.py:16:5 - error: Index 4 is out of range for type tuple[int, str, list[bool]] (reportGeneralTypeIssues)
+literals_interactions.py:17:5 - error: Index -4 is out of range for type tuple[int, str, list[bool]] (reportGeneralTypeIssues)
"""
conformance_automated = "Pass"
errors_diff = """
diff --git a/conformance/results/results.html b/conformance/results/results.html
index 249f6b70..adf3ffc2 100644
--- a/conformance/results/results.html
+++ b/conformance/results/results.html
@@ -569,11 +569,11 @@
Python Type System Conformance Test Results
Literals
| literals_interactions |
-Partial Does not narrow type of `x` with `x in Literal` type guard pattern. |
+Pass* Does not narrow `str` or `LiteralString` types to `Literal` string types via equality or containment checks. |
Pass |
Pass |
Pass |
-Partial Deliberately does not allow `str` to be narrowed to literal string types through equality or containment checks due to the possibility of `str` subclasses that could have unexpected equality semantics. |
+Pass* Deliberately does not allow `str` to be narrowed to literal string types through equality or containment checks due to the possibility of `str` subclasses that could have unexpected equality semantics. Incorrectly fails to narrow the type `LiteralString & ~Literal["MALFORMED"]` to `Literal["ABORTED"]` after an `== "ABORTED"` check. |
| literals_literalstring |
Unsupported Support for `LiteralString` is not implemented. |
diff --git a/conformance/results/ty/literals_interactions.toml b/conformance/results/ty/literals_interactions.toml
index 354e5a8f..3310f7c7 100644
--- a/conformance/results/ty/literals_interactions.toml
+++ b/conformance/results/ty/literals_interactions.toml
@@ -1,17 +1,18 @@
-conformance_automated = "Fail"
-conformant = "Partial"
+conformance_automated = "Pass"
notes = """
Deliberately does not allow `str` to be narrowed to literal string types through equality or containment checks due to the possibility of `str` subclasses that could have unexpected equality semantics.
+Incorrectly fails to narrow the type `LiteralString & ~Literal["MALFORMED"]` to `Literal["ABORTED"]` after an `== "ABORTED"` check.
"""
errors_diff = """
-Line 106: Unexpected errors ['literals_interactions.py:106:35: error[invalid-argument-type] Argument to function `expects_bad_status` is incorrect: Expected `Literal["MALFORMED", "ABORTED"]`, found `str`']
-Line 109: Unexpected errors ['literals_interactions.py:109:32: error[invalid-argument-type] Argument to function `expects_pending_status` is incorrect: Expected `Literal["PENDING"]`, found `str`']
"""
output = """
-literals_interactions.py:15:5: error[index-out-of-bounds] Index 5 is out of bounds for tuple `tuple[int, str, list[bool]]` with length 3
-literals_interactions.py:16:5: error[index-out-of-bounds] Index -5 is out of bounds for tuple `tuple[int, str, list[bool]]` with length 3
-literals_interactions.py:17:5: error[index-out-of-bounds] Index 4 is out of bounds for tuple `tuple[int, str, list[bool]]` with length 3
-literals_interactions.py:18:5: error[index-out-of-bounds] Index -4 is out of bounds for tuple `tuple[int, str, list[bool]]` with length 3
-literals_interactions.py:106:35: error[invalid-argument-type] Argument to function `expects_bad_status` is incorrect: Expected `Literal["MALFORMED", "ABORTED"]`, found `str`
-literals_interactions.py:109:32: error[invalid-argument-type] Argument to function `expects_pending_status` is incorrect: Expected `Literal["PENDING"]`, found `str`
+literals_interactions.py:14:5: error[index-out-of-bounds] Index 5 is out of bounds for tuple `tuple[int, str, list[bool]]` with length 3
+literals_interactions.py:15:5: error[index-out-of-bounds] Index -5 is out of bounds for tuple `tuple[int, str, list[bool]]` with length 3
+literals_interactions.py:16:5: error[index-out-of-bounds] Index 4 is out of bounds for tuple `tuple[int, str, list[bool]]` with length 3
+literals_interactions.py:17:5: error[index-out-of-bounds] Index -4 is out of bounds for tuple `tuple[int, str, list[bool]]` with length 3
+literals_interactions.py:113:28: error[invalid-argument-type] Argument to function `expects_bad_status` is incorrect: Expected `Literal["MALFORMED", "ABORTED"]`, found `LiteralString & ~Literal["MALFORMED"]`
+literals_interactions.py:128:28: error[invalid-argument-type] Argument to function `expects_bad_status` is incorrect: Expected `Literal["MALFORMED", "ABORTED"]`, found `str`
+literals_interactions.py:130:28: error[invalid-argument-type] Argument to function `expects_bad_status` is incorrect: Expected `Literal["MALFORMED", "ABORTED"]`, found `str & ~Literal["MALFORMED"]`
+literals_interactions.py:133:28: error[invalid-argument-type] Argument to function `expects_bad_status` is incorrect: Expected `Literal["MALFORMED", "ABORTED"]`, found `str`
+literals_interactions.py:136:32: error[invalid-argument-type] Argument to function `expects_pending_status` is incorrect: Expected `Literal["PENDING"]`, found `str`
"""
diff --git a/conformance/results/zuban/literals_interactions.toml b/conformance/results/zuban/literals_interactions.toml
index 242baa2f..16633617 100644
--- a/conformance/results/zuban/literals_interactions.toml
+++ b/conformance/results/zuban/literals_interactions.toml
@@ -2,8 +2,8 @@ conformance_automated = "Pass"
errors_diff = """
"""
output = """
+literals_interactions.py:14: error: Tuple index out of range [misc]
literals_interactions.py:15: error: Tuple index out of range [misc]
literals_interactions.py:16: error: Tuple index out of range [misc]
literals_interactions.py:17: error: Tuple index out of range [misc]
-literals_interactions.py:18: error: Tuple index out of range [misc]
"""
diff --git a/conformance/tests/literals_interactions.py b/conformance/tests/literals_interactions.py
index b7277325..47412676 100644
--- a/conformance/tests/literals_interactions.py
+++ b/conformance/tests/literals_interactions.py
@@ -3,9 +3,8 @@
"""
# Specification: https://typing.readthedocs.io/en/latest/spec/literal.html#interactions-with-other-types-and-features
-
from enum import Enum
-from typing import IO, Any, Final, Generic, Literal, TypeVar, assert_type, overload
+from typing import IO, Any, Final, Generic, Literal, TypeVar, LiteralString, assert_type, overload
def func1(v: tuple[int, str, list[bool]], a: Literal[0], b: Literal[5], c: Literal[-5]):
@@ -93,6 +92,12 @@ def parse_status1(s: str | Status) -> None:
assert_type(s, str)
+# > 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:
+
def expects_bad_status(status: Literal["MALFORMED", "ABORTED"]):
...
@@ -101,12 +106,34 @@ def expects_pending_status(status: Literal["PENDING"]):
...
-def parse_status2(status: str) -> None:
+def parse_status2(status: LiteralString) -> None:
+ if status == "MALFORMED":
+ expects_bad_status(status) # E? narrowing the type here is sound, but optional per the spec
+ elif status == "ABORTED":
+ expects_bad_status(status) # E? narrowing the type here is sound, but optional per the spec
+
+ if status in ("MALFORMED", "ABORTED"):
+ expects_bad_status(status) # E? narrowing the type here is sound, but optional per the spec
+
+ if status == "PENDING":
+ expects_pending_status(status) # E? narrowing the type here is sound, but optional per the spec
+
+
+# Narrowing `str` to `Literal` strings is unsound given the possiblity of
+# user-defined `str` subclasses that could have custom equality semantics,
+# but is explicitly listed by the spec as optional analysis that type checkers
+# may perform.
+def parse_status3(status: str) -> None:
+ if status == "MALFORMED":
+ expects_bad_status(status) # E? narrowing the type here is unsound, but allowed per the spec
+ elif status == "ABORTED":
+ expects_bad_status(status) # E? narrowing the type here is unsound, but allowed per the spec
+
if status in ("MALFORMED", "ABORTED"):
- return expects_bad_status(status)
+ expects_bad_status(status) # E? narrowing the type here is unsound, but allowed per the spec
if status == "PENDING":
- expects_pending_status(status)
+ expects_pending_status(status) # E? narrowing the type here is unsound, but allowed per the spec
final_val1: Final = 3
|---|