ruff/crates/red_knot_python_semantic/resources/mdtest/subscript/string.md
David Peter 56c796acee
[red-knot] Slice expression types & subscript expressions with slices (#13917)
## Summary

- Add a new `Type::SliceLiteral` variant
- Infer `SliceLiteral` types for slice expressions, such as
`<int-literal>:<int-literal>:<int-literal>`.
- Infer "sliced" literal types for subscript expressions using slices,
such as `<string-literal>[<slice-literal>]`.
- Infer types for expressions involving slices of tuples:
`<tuple>[<slice-literal>]`.

closes #13853

## Test Plan

- Unit tests for indexing/slicing utility functions
- Markdown-based tests for
  - Subscript expressions `tuple[slice]`
  - Subscript expressions `string_literal[slice]`
  - Subscript expressions `bytes_literal[slice]`
2024-10-29 10:17:31 +01:00

2.7 KiB

String subscripts

Indexing

s = "abcde"

reveal_type(s[0])  # revealed: Literal["a"]
reveal_type(s[1])  # revealed: Literal["b"]
reveal_type(s[-1])  # revealed: Literal["e"]
reveal_type(s[-2])  # revealed: Literal["d"]

reveal_type(s[False])  # revealed: Literal["a"]
reveal_type(s[True])  # revealed: Literal["b"]

a = s[8]  # error: [index-out-of-bounds] "Index 8 is out of bounds for string `Literal["abcde"]` with length 5"
reveal_type(a)  # revealed: Unknown

b = s[-8]  # error: [index-out-of-bounds] "Index -8 is out of bounds for string `Literal["abcde"]` with length 5"
reveal_type(b)  # revealed: Unknown

def int_instance() -> int: ...

a = "abcde"[int_instance()]
# TODO: Support overloads... Should be `str`
reveal_type(a)  # revealed: @Todo

Slices

s = "abcde"

reveal_type(s[0:0])  # revealed: Literal[""]
reveal_type(s[0:1])  # revealed: Literal["a"]
reveal_type(s[0:2])  # revealed: Literal["ab"]
reveal_type(s[0:5])  # revealed: Literal["abcde"]
reveal_type(s[0:6])  # revealed: Literal["abcde"]
reveal_type(s[1:3])  # revealed: Literal["bc"]

reveal_type(s[-3:5])  # revealed: Literal["cde"]
reveal_type(s[-4:-2])  # revealed: Literal["bc"]
reveal_type(s[-10:10])  # revealed: Literal["abcde"]

reveal_type(s[0:])  # revealed: Literal["abcde"]
reveal_type(s[2:])  # revealed: Literal["cde"]
reveal_type(s[5:])  # revealed: Literal[""]
reveal_type(s[:2])  # revealed: Literal["ab"]
reveal_type(s[:0])  # revealed: Literal[""]
reveal_type(s[:2])  # revealed: Literal["ab"]
reveal_type(s[:10])  # revealed: Literal["abcde"]
reveal_type(s[:])  # revealed: Literal["abcde"]

reveal_type(s[::-1])  # revealed: Literal["edcba"]
reveal_type(s[::2])  # revealed: Literal["ace"]
reveal_type(s[-2:-5:-1])  # revealed: Literal["dcb"]
reveal_type(s[::-2])  # revealed: Literal["eca"]
reveal_type(s[-1::-3])  # revealed: Literal["eb"]

reveal_type(s[None:2:None])  # revealed: Literal["ab"]
reveal_type(s[1:None:1])  # revealed: Literal["bcde"]
reveal_type(s[None:None:None])  # revealed: Literal["abcde"]

start = 1
stop = None
step = 2
reveal_type(s[start:stop:step])  # revealed: Literal["bd"]

reveal_type(s[False:True])  # revealed: Literal["a"]
reveal_type(s[True:3])  # revealed: Literal["bc"]

s[0:4:0]  # error: [zero-stepsize-in-slice]
s[:4:0]  # error: [zero-stepsize-in-slice]
s[0::0]  # error: [zero-stepsize-in-slice]
s[::0]  # error: [zero-stepsize-in-slice]

def int_instance() -> int: ...

substring1 = s[int_instance() : int_instance()]
# TODO: Support overloads... Should be `LiteralString`
reveal_type(substring1)  # revealed: @Todo

def str_instance() -> str: ...

substring2 = str_instance()[0:5]
# TODO: Support overloads... Should be `str`
reveal_type(substring2)  # revealed: @Todo