diff --git a/crates/ty/docs/rules.md b/crates/ty/docs/rules.md index ee58180199..8de896c0c6 100644 --- a/crates/ty/docs/rules.md +++ b/crates/ty/docs/rules.md @@ -2005,30 +2005,6 @@ def func(x: bool): ... func("string") # error: [no-matching-overload] ``` -## `non-subscriptable` - - -Default level: error · -Added in 0.0.1-alpha.1 · -Related issues · -View source - - - -**What it does** - -Checks for subscripting objects that do not support subscripting. - -**Why is this bad?** - -Subscripting an object that does not support it will raise a `TypeError` at runtime. - -**Examples** - -```python -4[1] # TypeError: 'int' object is not subscriptable -``` - ## `not-iterable` @@ -2055,6 +2031,30 @@ for i in 34: # TypeError: 'int' object is not iterable pass ``` +## `not-subscriptable` + + +Default level: error · +Added in 0.0.1-alpha.1 · +Related issues · +View source + + + +**What it does** + +Checks for subscripting objects that do not support subscripting. + +**Why is this bad?** + +Subscripting an object that does not support it will raise a `TypeError` at runtime. + +**Examples** + +```python +4[1] # TypeError: 'int' object is not subscriptable +``` + ## `override-of-final-method` diff --git a/crates/ty/tests/cli/exit_code.rs b/crates/ty/tests/cli/exit_code.rs index 7c63564ef1..35e4f50ad0 100644 --- a/crates/ty/tests/cli/exit_code.rs +++ b/crates/ty/tests/cli/exit_code.rs @@ -149,7 +149,7 @@ fn both_warnings_and_errors() -> anyhow::Result<()> { "test.py", r#" print(x) # [unresolved-reference] - print(4[1]) # [non-subscriptable] + print(4[1]) # [not-subscriptable] "#, )?; @@ -162,18 +162,18 @@ fn both_warnings_and_errors() -> anyhow::Result<()> { | 2 | print(x) # [unresolved-reference] | ^ - 3 | print(4[1]) # [non-subscriptable] + 3 | print(4[1]) # [not-subscriptable] | info: rule `unresolved-reference` was selected on the command line - error[non-subscriptable]: Cannot subscript object of type `Literal[4]` with no `__getitem__` method + error[not-subscriptable]: Cannot subscript object of type `Literal[4]` with no `__getitem__` method --> test.py:3:7 | 2 | print(x) # [unresolved-reference] - 3 | print(4[1]) # [non-subscriptable] + 3 | print(4[1]) # [not-subscriptable] | ^^^^ | - info: rule `non-subscriptable` is enabled by default + info: rule `not-subscriptable` is enabled by default Found 2 diagnostics @@ -189,7 +189,7 @@ fn both_warnings_and_errors_and_error_on_warning_is_true() -> anyhow::Result<()> "test.py", r###" print(x) # [unresolved-reference] - print(4[1]) # [non-subscriptable] + print(4[1]) # [not-subscriptable] "###, )?; @@ -202,18 +202,18 @@ fn both_warnings_and_errors_and_error_on_warning_is_true() -> anyhow::Result<()> | 2 | print(x) # [unresolved-reference] | ^ - 3 | print(4[1]) # [non-subscriptable] + 3 | print(4[1]) # [not-subscriptable] | info: rule `unresolved-reference` was selected on the command line - error[non-subscriptable]: Cannot subscript object of type `Literal[4]` with no `__getitem__` method + error[not-subscriptable]: Cannot subscript object of type `Literal[4]` with no `__getitem__` method --> test.py:3:7 | 2 | print(x) # [unresolved-reference] - 3 | print(4[1]) # [non-subscriptable] + 3 | print(4[1]) # [not-subscriptable] | ^^^^ | - info: rule `non-subscriptable` is enabled by default + info: rule `not-subscriptable` is enabled by default Found 2 diagnostics @@ -229,7 +229,7 @@ fn exit_zero_is_true() -> anyhow::Result<()> { "test.py", r#" print(x) # [unresolved-reference] - print(4[1]) # [non-subscriptable] + print(4[1]) # [not-subscriptable] "#, )?; @@ -242,18 +242,18 @@ fn exit_zero_is_true() -> anyhow::Result<()> { | 2 | print(x) # [unresolved-reference] | ^ - 3 | print(4[1]) # [non-subscriptable] + 3 | print(4[1]) # [not-subscriptable] | info: rule `unresolved-reference` was selected on the command line - error[non-subscriptable]: Cannot subscript object of type `Literal[4]` with no `__getitem__` method + error[not-subscriptable]: Cannot subscript object of type `Literal[4]` with no `__getitem__` method --> test.py:3:7 | 2 | print(x) # [unresolved-reference] - 3 | print(4[1]) # [non-subscriptable] + 3 | print(4[1]) # [not-subscriptable] | ^^^^ | - info: rule `non-subscriptable` is enabled by default + info: rule `not-subscriptable` is enabled by default Found 2 diagnostics diff --git a/crates/ty/tests/cli/main.rs b/crates/ty/tests/cli/main.rs index 2004a91368..d50ca21c72 100644 --- a/crates/ty/tests/cli/main.rs +++ b/crates/ty/tests/cli/main.rs @@ -634,7 +634,7 @@ fn concise_diagnostics() -> anyhow::Result<()> { "test.py", r#" print(x) # [unresolved-reference] - print(4[1]) # [non-subscriptable] + print(4[1]) # [not-subscriptable] "#, )?; @@ -643,7 +643,7 @@ fn concise_diagnostics() -> anyhow::Result<()> { exit_code: 1 ----- stdout ----- test.py:2:7: warning[unresolved-reference] Name `x` used when not defined - test.py:3:7: error[non-subscriptable] Cannot subscript object of type `Literal[4]` with no `__getitem__` method + test.py:3:7: error[not-subscriptable] Cannot subscript object of type `Literal[4]` with no `__getitem__` method Found 2 diagnostics ----- stderr ----- @@ -658,7 +658,7 @@ fn gitlab_diagnostics() -> anyhow::Result<()> { "test.py", r#" print(x) # [unresolved-reference] - print(4[1]) # [non-subscriptable] + print(4[1]) # [not-subscriptable] from typing_extensions import reveal_type reveal_type('str'.lower()) # [revealed-type] "#, @@ -694,8 +694,8 @@ fn gitlab_diagnostics() -> anyhow::Result<()> { } }, { - "check_name": "non-subscriptable", - "description": "non-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method", + "check_name": "not-subscriptable", + "description": "not-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method", "severity": "major", "fingerprint": "[FINGERPRINT]", "location": { @@ -744,7 +744,7 @@ fn github_diagnostics() -> anyhow::Result<()> { "test.py", r#" print(x) # [unresolved-reference] - print(4[1]) # [non-subscriptable] + print(4[1]) # [not-subscriptable] from typing_extensions import reveal_type reveal_type('str'.lower()) # [revealed-type] "#, @@ -755,7 +755,7 @@ fn github_diagnostics() -> anyhow::Result<()> { exit_code: 1 ----- stdout ----- ::warning title=ty (unresolved-reference),file=/test.py,line=2,col=7,endLine=2,endColumn=8::test.py:2:7: unresolved-reference: Name `x` used when not defined - ::error title=ty (non-subscriptable),file=/test.py,line=3,col=7,endLine=3,endColumn=11::test.py:3:7: non-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method + ::error title=ty (not-subscriptable),file=/test.py,line=3,col=7,endLine=3,endColumn=11::test.py:3:7: not-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method ::notice title=ty (revealed-type),file=/test.py,line=5,col=13,endLine=5,endColumn=26::test.py:5:13: revealed-type: Revealed type: `LiteralString` ----- stderr ----- diff --git a/crates/ty_python_semantic/resources/mdtest/call/dunder.md b/crates/ty_python_semantic/resources/mdtest/call/dunder.md index f7be30464c..56c7e5d8ad 100644 --- a/crates/ty_python_semantic/resources/mdtest/call/dunder.md +++ b/crates/ty_python_semantic/resources/mdtest/call/dunder.md @@ -53,7 +53,7 @@ class ClassWithNormalDunder: def __getitem__(self, key: int) -> str: return str(key) -# error: [non-subscriptable] +# error: [not-subscriptable] ClassWithNormalDunder[0] ``` @@ -85,7 +85,7 @@ class ThisFails: this_fails = ThisFails() -# error: [non-subscriptable] "Cannot subscript object of type `ThisFails` with no `__getitem__` method" +# error: [not-subscriptable] "Cannot subscript object of type `ThisFails` with no `__getitem__` method" reveal_type(this_fails[0]) # revealed: Unknown ``` @@ -259,8 +259,8 @@ class NotSubscriptable2: self.__getitem__ = external_getitem def _(union: NotSubscriptable1 | NotSubscriptable2): - # error: [non-subscriptable] "Cannot subscript object of type `NotSubscriptable2` with no `__getitem__` method" - # error: [non-subscriptable] "Cannot subscript object of type `NotSubscriptable1` with no `__getitem__` method" + # error: [not-subscriptable] "Cannot subscript object of type `NotSubscriptable2` with no `__getitem__` method" + # error: [not-subscriptable] "Cannot subscript object of type `NotSubscriptable1` with no `__getitem__` method" union[0] ``` diff --git a/crates/ty_python_semantic/resources/mdtest/class/super.md b/crates/ty_python_semantic/resources/mdtest/class/super.md index 3b7989386e..de5fe0b3dd 100644 --- a/crates/ty_python_semantic/resources/mdtest/class/super.md +++ b/crates/ty_python_semantic/resources/mdtest/class/super.md @@ -667,6 +667,6 @@ class B(A): ... reveal_type(A()[0]) # revealed: int reveal_type(super(B, B()).__getitem__) # revealed: bound method B.__getitem__(key: int) -> int -# error: [non-subscriptable] "Cannot subscript object of type `, B>` with no `__getitem__` method" +# error: [not-subscriptable] "Cannot subscript object of type `, B>` with no `__getitem__` method" super(B, B())[0] ``` diff --git a/crates/ty_python_semantic/resources/mdtest/del.md b/crates/ty_python_semantic/resources/mdtest/del.md index 5703b26c35..945502ee82 100644 --- a/crates/ty_python_semantic/resources/mdtest/del.md +++ b/crates/ty_python_semantic/resources/mdtest/del.md @@ -216,7 +216,7 @@ class OnlyDelItem: d = OnlyDelItem() del d[0] # OK -# error: [non-subscriptable] "Cannot subscript object of type `OnlyDelItem` with no `__getitem__` method" +# error: [not-subscriptable] "Cannot subscript object of type `OnlyDelItem` with no `__getitem__` method" d[0] ``` @@ -232,7 +232,7 @@ class OnlyGetItem: g = OnlyGetItem() reveal_type(g[0]) # revealed: str -# error: [non-subscriptable] "Cannot delete subscript on object of type `OnlyGetItem` with no `__delitem__` method" +# error: [not-subscriptable] "Cannot delete subscript on object of type `OnlyGetItem` with no `__delitem__` method" del g[0] ``` diff --git a/crates/ty_python_semantic/resources/mdtest/generics/pep695/aliases.md b/crates/ty_python_semantic/resources/mdtest/generics/pep695/aliases.md index 5d349e5034..857cdcd2b6 100644 --- a/crates/ty_python_semantic/resources/mdtest/generics/pep695/aliases.md +++ b/crates/ty_python_semantic/resources/mdtest/generics/pep695/aliases.md @@ -72,32 +72,32 @@ from typing import TypeVar, Protocol, TypedDict type B = ... -# error: [non-subscriptable] "Cannot subscript non-generic type alias" +# error: [not-subscriptable] "Cannot subscript non-generic type alias" reveal_type(B[int]) # revealed: Unknown -# error: [non-subscriptable] "Cannot subscript non-generic type alias" +# error: [not-subscriptable] "Cannot subscript non-generic type alias" def _(b: B[int]): reveal_type(b) # revealed: Unknown type IntOrStr = int | str -# error: [non-subscriptable] "Cannot subscript non-generic type alias" +# error: [not-subscriptable] "Cannot subscript non-generic type alias" def _(c: IntOrStr[int]): reveal_type(c) # revealed: Unknown type ListOfInts = list[int] -# error: [non-subscriptable] "Cannot subscript non-generic type alias: `list[int]` is already specialized" +# error: [not-subscriptable] "Cannot subscript non-generic type alias: `list[int]` is already specialized" def _(l: ListOfInts[int]): reveal_type(l) # revealed: Unknown type List[T] = list[T] -# error: [non-subscriptable] "Cannot subscript non-generic type alias: Double specialization is not allowed" +# error: [not-subscriptable] "Cannot subscript non-generic type alias: Double specialization is not allowed" def _(l: List[int][int]): reveal_type(l) # revealed: Unknown -# error: [non-subscriptable] "Cannot subscript non-generic type: `` is already specialized" +# error: [not-subscriptable] "Cannot subscript non-generic type: `` is already specialized" type DoubleSpecialization[T] = list[T][T] def _(d: DoubleSpecialization[int]): @@ -105,7 +105,7 @@ def _(d: DoubleSpecialization[int]): type Tuple = tuple[int, str] -# error: [non-subscriptable] "Cannot subscript non-generic type alias: `tuple[int, str]` is already specialized" +# error: [not-subscriptable] "Cannot subscript non-generic type alias: `tuple[int, str]` is already specialized" def _(doubly_specialized: Tuple[int]): reveal_type(doubly_specialized) # revealed: Unknown @@ -116,7 +116,7 @@ class LegacyProto(Protocol[T]): type LegacyProtoInt = LegacyProto[int] -# error: [non-subscriptable] "Cannot subscript non-generic type alias: `LegacyProto[int]` is already specialized" +# error: [not-subscriptable] "Cannot subscript non-generic type alias: `LegacyProto[int]` is already specialized" def _(x: LegacyProtoInt[int]): reveal_type(x) # revealed: Unknown @@ -125,7 +125,7 @@ class Proto[T](Protocol): type ProtoInt = Proto[int] -# error: [non-subscriptable] "Cannot subscript non-generic type alias: `Proto[int]` is already specialized" +# error: [not-subscriptable] "Cannot subscript non-generic type alias: `Proto[int]` is already specialized" def _(x: ProtoInt[int]): reveal_type(x) # revealed: Unknown @@ -135,7 +135,7 @@ class LegacyDict(TypedDict[T]): type LegacyDictInt = LegacyDict[int] -# error: [non-subscriptable] "Cannot subscript non-generic type alias" +# error: [not-subscriptable] "Cannot subscript non-generic type alias" def _(x: LegacyDictInt[int]): reveal_type(x) # revealed: Unknown @@ -144,13 +144,13 @@ class Dict[T](TypedDict): type DictInt = Dict[int] -# error: [non-subscriptable] "Cannot subscript non-generic type alias: `Dict[int]` is already specialized" +# error: [not-subscriptable] "Cannot subscript non-generic type alias: `Dict[int]` is already specialized" def _(x: DictInt[int]): reveal_type(x) # revealed: Unknown type Union = list[str] | list[int] -# error: [non-subscriptable] "Cannot subscript non-generic type alias: `list[str] | list[int]` is already specialized" +# error: [not-subscriptable] "Cannot subscript non-generic type alias: `list[str] | list[int]` is already specialized" def _(x: Union[int]): reveal_type(x) # revealed: Unknown ``` diff --git a/crates/ty_python_semantic/resources/mdtest/implicit_type_aliases.md b/crates/ty_python_semantic/resources/mdtest/implicit_type_aliases.md index c5f7cf79ef..e3fff99f0d 100644 --- a/crates/ty_python_semantic/resources/mdtest/implicit_type_aliases.md +++ b/crates/ty_python_semantic/resources/mdtest/implicit_type_aliases.md @@ -664,18 +664,18 @@ from typing import Protocol, TypeVar, TypedDict ListOfInts = list[int] -# error: [non-subscriptable] "Cannot subscript non-generic type: `` is already specialized" +# error: [not-subscriptable] "Cannot subscript non-generic type: `` is already specialized" def _(doubly_specialized: ListOfInts[int]): reveal_type(doubly_specialized) # revealed: Unknown type ListOfInts2 = list[int] -# error: [non-subscriptable] "Cannot subscript non-generic type alias: `list[int]` is already specialized" +# error: [not-subscriptable] "Cannot subscript non-generic type alias: `list[int]` is already specialized" DoublySpecialized = ListOfInts2[int] def _(doubly_specialized: DoublySpecialized): reveal_type(doubly_specialized) # revealed: Unknown -# error: [non-subscriptable] "Cannot subscript non-generic type: `` is already specialized" +# error: [not-subscriptable] "Cannot subscript non-generic type: `` is already specialized" List = list[int][int] def _(doubly_specialized: List): @@ -683,7 +683,7 @@ def _(doubly_specialized: List): Tuple = tuple[int, str] -# error: [non-subscriptable] "Cannot subscript non-generic type: `` is already specialized" +# error: [not-subscriptable] "Cannot subscript non-generic type: `` is already specialized" def _(doubly_specialized: Tuple[int]): reveal_type(doubly_specialized) # revealed: Unknown @@ -694,7 +694,7 @@ class LegacyProto(Protocol[T]): LegacyProtoInt = LegacyProto[int] -# error: [non-subscriptable] "Cannot subscript non-generic type: `` is already specialized" +# error: [not-subscriptable] "Cannot subscript non-generic type: `` is already specialized" def _(doubly_specialized: LegacyProtoInt[int]): reveal_type(doubly_specialized) # revealed: Unknown @@ -703,7 +703,7 @@ class Proto[T](Protocol): ProtoInt = Proto[int] -# error: [non-subscriptable] "Cannot subscript non-generic type: `` is already specialized" +# error: [not-subscriptable] "Cannot subscript non-generic type: `` is already specialized" def _(doubly_specialized: ProtoInt[int]): reveal_type(doubly_specialized) # revealed: Unknown @@ -711,10 +711,10 @@ def _(doubly_specialized: ProtoInt[int]): class LegacyDict(TypedDict[T]): x: T -# TODO: should be a `non-subscriptable` error +# TODO: should be a `not-subscriptable` error LegacyDictInt = LegacyDict[int] -# TODO: should be a `non-subscriptable` error +# TODO: should be a `not-subscriptable` error def _(doubly_specialized: LegacyDictInt[int]): # TODO: should be `Unknown` reveal_type(doubly_specialized) # revealed: @Todo(Inference of subscript on special form) @@ -724,20 +724,20 @@ class Dict[T](TypedDict): DictInt = Dict[int] -# error: [non-subscriptable] "Cannot subscript non-generic type: `` is already specialized" +# error: [not-subscriptable] "Cannot subscript non-generic type: `` is already specialized" def _(doubly_specialized: DictInt[int]): reveal_type(doubly_specialized) # revealed: Unknown Union = list[str] | list[int] -# error: [non-subscriptable] "Cannot subscript non-generic type: `` is already specialized" +# error: [not-subscriptable] "Cannot subscript non-generic type: `` is already specialized" def _(doubly_specialized: Union[int]): reveal_type(doubly_specialized) # revealed: Unknown type MyListAlias[T] = list[T] MyListOfInts = MyListAlias[int] -# error: [non-subscriptable] "Cannot subscript non-generic type alias: Double specialization is not allowed" +# error: [not-subscriptable] "Cannot subscript non-generic type alias: Double specialization is not allowed" def _(doubly_specialized: MyListOfInts[int]): reveal_type(doubly_specialized) # revealed: Unknown ``` @@ -775,7 +775,7 @@ def this_does_not_work() -> TypeOf[IntOrStr]: raise NotImplementedError() def _( - # error: [non-subscriptable] "Cannot subscript non-generic type" + # error: [not-subscriptable] "Cannot subscript non-generic type" specialized: this_does_not_work()[int], ): reveal_type(specialized) # revealed: Unknown @@ -784,7 +784,7 @@ def _( Similarly, if you try to specialize a union type without a binding context, we emit an error: ```py -# error: [non-subscriptable] "Cannot subscript non-generic type" +# error: [not-subscriptable] "Cannot subscript non-generic type" x: (list[T] | set[T])[int] def _(): diff --git a/crates/ty_python_semantic/resources/mdtest/narrow/assignment.md b/crates/ty_python_semantic/resources/mdtest/narrow/assignment.md index e3bf51685c..752d08d216 100644 --- a/crates/ty_python_semantic/resources/mdtest/narrow/assignment.md +++ b/crates/ty_python_semantic/resources/mdtest/narrow/assignment.md @@ -247,11 +247,11 @@ does["not"]["exist"] = 0 # error: [unresolved-reference] reveal_type(does["not"]["exist"]) # revealed: Unknown -non_subscriptable = 1 +not_subscriptable = 1 # error: [invalid-assignment] -non_subscriptable[0] = 0 -# error: [non-subscriptable] -reveal_type(non_subscriptable[0]) # revealed: Unknown +not_subscriptable[0] = 0 +# error: [not-subscriptable] +reveal_type(not_subscriptable[0]) # revealed: Unknown ``` ### No narrowing for custom classes with arbitrary `__getitem__` / `__setitem__` diff --git a/crates/ty_python_semantic/resources/mdtest/snapshots/instance.md_-_Instance_subscript_-_`__getitem__`_unboun…_(b1b0f9ed2b7302b2).snap b/crates/ty_python_semantic/resources/mdtest/snapshots/instance.md_-_Instance_subscript_-_`__getitem__`_unboun…_(b1b0f9ed2b7302b2).snap index cf32516a0f..e196045527 100644 --- a/crates/ty_python_semantic/resources/mdtest/snapshots/instance.md_-_Instance_subscript_-_`__getitem__`_unboun…_(b1b0f9ed2b7302b2).snap +++ b/crates/ty_python_semantic/resources/mdtest/snapshots/instance.md_-_Instance_subscript_-_`__getitem__`_unboun…_(b1b0f9ed2b7302b2).snap @@ -14,20 +14,20 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/subscript/instance.md ``` 1 | class NotSubscriptable: ... 2 | -3 | a = NotSubscriptable()[0] # error: [non-subscriptable] +3 | a = NotSubscriptable()[0] # error: [not-subscriptable] ``` # Diagnostics ``` -error[non-subscriptable]: Cannot subscript object of type `NotSubscriptable` with no `__getitem__` method +error[not-subscriptable]: Cannot subscript object of type `NotSubscriptable` with no `__getitem__` method --> src/mdtest_snippet.py:3:5 | 1 | class NotSubscriptable: ... 2 | -3 | a = NotSubscriptable()[0] # error: [non-subscriptable] +3 | a = NotSubscriptable()[0] # error: [not-subscriptable] | ^^^^^^^^^^^^^^^^^^^^^ | -info: rule `non-subscriptable` is enabled by default +info: rule `not-subscriptable` is enabled by default ``` diff --git a/crates/ty_python_semantic/resources/mdtest/subscript/class.md b/crates/ty_python_semantic/resources/mdtest/subscript/class.md index 947f7fbbaf..1c14dd23a5 100644 --- a/crates/ty_python_semantic/resources/mdtest/subscript/class.md +++ b/crates/ty_python_semantic/resources/mdtest/subscript/class.md @@ -69,7 +69,7 @@ def _(flag: bool): else: class Spam: ... - # error: [non-subscriptable] "Cannot subscript object of type `` with no `__class_getitem__` method" + # error: [not-subscriptable] "Cannot subscript object of type `` with no `__class_getitem__` method" # revealed: str | Unknown reveal_type(Spam[42]) ``` diff --git a/crates/ty_python_semantic/resources/mdtest/subscript/instance.md b/crates/ty_python_semantic/resources/mdtest/subscript/instance.md index 90c9c07b87..e9691f255a 100644 --- a/crates/ty_python_semantic/resources/mdtest/subscript/instance.md +++ b/crates/ty_python_semantic/resources/mdtest/subscript/instance.md @@ -7,7 +7,7 @@ ```py class NotSubscriptable: ... -a = NotSubscriptable()[0] # error: [non-subscriptable] +a = NotSubscriptable()[0] # error: [not-subscriptable] ``` ## `__getitem__` not callable diff --git a/crates/ty_python_semantic/resources/mdtest/subscript/tuple.md b/crates/ty_python_semantic/resources/mdtest/subscript/tuple.md index fd909aee41..1ec85b3203 100644 --- a/crates/ty_python_semantic/resources/mdtest/subscript/tuple.md +++ b/crates/ty_python_semantic/resources/mdtest/subscript/tuple.md @@ -416,7 +416,7 @@ def test2(val: tuple[str, None] | list[int | float]): ```py def test3(val: tuple[str] | tuple[int] | int): - # error: [non-subscriptable] "Cannot subscript object of type `int` with no `__getitem__` method" + # error: [not-subscriptable] "Cannot subscript object of type `int` with no `__getitem__` method" reveal_type(val[0]) # revealed: str | int | Unknown ``` diff --git a/crates/ty_python_semantic/src/types/diagnostic.rs b/crates/ty_python_semantic/src/types/diagnostic.rs index 10acd6d231..1657487dab 100644 --- a/crates/ty_python_semantic/src/types/diagnostic.rs +++ b/crates/ty_python_semantic/src/types/diagnostic.rs @@ -94,7 +94,7 @@ pub(crate) fn register_lints(registry: &mut LintRegistryBuilder) { registry.register_lint(&INVALID_TYPE_VARIABLE_CONSTRAINTS); registry.register_lint(&MISSING_ARGUMENT); registry.register_lint(&NO_MATCHING_OVERLOAD); - registry.register_lint(&NON_SUBSCRIPTABLE); + registry.register_lint(&NOT_SUBSCRIPTABLE); registry.register_lint(&NOT_ITERABLE); registry.register_lint(&UNSUPPORTED_BOOL_CONVERSION); registry.register_lint(&PARAMETER_ALREADY_ASSIGNED); @@ -1461,7 +1461,7 @@ declare_lint! { /// ```python /// 4[1] # TypeError: 'int' object is not subscriptable /// ``` - pub(crate) static NON_SUBSCRIPTABLE = { + pub(crate) static NOT_SUBSCRIPTABLE = { summary: "detects subscripting objects that do not support subscripting", status: LintStatus::stable("0.0.1-alpha.1"), default_level: Level::Error, @@ -2402,24 +2402,24 @@ pub(super) fn report_index_out_of_bounds( } /// Emit a diagnostic declaring that a type does not support subscripting. -pub(super) fn report_non_subscriptable( +pub(super) fn report_not_subscriptable( context: &InferContext, node: &ast::ExprSubscript, - non_subscriptable_ty: Type, + not_subscriptable_ty: Type, method: &str, ) { - let Some(builder) = context.report_lint(&NON_SUBSCRIPTABLE, node) else { + let Some(builder) = context.report_lint(&NOT_SUBSCRIPTABLE, node) else { return; }; if method == "__delitem__" { builder.into_diagnostic(format_args!( "Cannot delete subscript on object of type `{}` with no `{method}` method", - non_subscriptable_ty.display(context.db()) + not_subscriptable_ty.display(context.db()) )); } else { builder.into_diagnostic(format_args!( "Cannot subscript object of type `{}` with no `{method}` method", - non_subscriptable_ty.display(context.db()) + not_subscriptable_ty.display(context.db()) )); } } diff --git a/crates/ty_python_semantic/src/types/infer/builder.rs b/crates/ty_python_semantic/src/types/infer/builder.rs index 0ea7b471ab..e253f4d133 100644 --- a/crates/ty_python_semantic/src/types/infer/builder.rs +++ b/crates/ty_python_semantic/src/types/infer/builder.rs @@ -63,7 +63,7 @@ use crate::types::diagnostic::{ INVALID_LEGACY_TYPE_VARIABLE, INVALID_METACLASS, INVALID_NAMED_TUPLE, INVALID_NEWTYPE, INVALID_OVERLOAD, INVALID_PARAMETER_DEFAULT, INVALID_PARAMSPEC, INVALID_PROTOCOL, INVALID_TYPE_ARGUMENTS, INVALID_TYPE_FORM, INVALID_TYPE_GUARD_CALL, - INVALID_TYPE_VARIABLE_CONSTRAINTS, IncompatibleBases, NON_SUBSCRIPTABLE, + INVALID_TYPE_VARIABLE_CONSTRAINTS, IncompatibleBases, NOT_SUBSCRIPTABLE, POSSIBLY_MISSING_ATTRIBUTE, POSSIBLY_MISSING_IMPLICIT_CALL, POSSIBLY_MISSING_IMPORT, SUBCLASS_OF_FINAL_CLASS, TypedDictDeleteErrorKind, UNDEFINED_REVEAL, UNRESOLVED_ATTRIBUTE, UNRESOLVED_GLOBAL, UNRESOLVED_IMPORT, UNRESOLVED_REFERENCE, UNSUPPORTED_OPERATOR, @@ -80,7 +80,7 @@ use crate::types::diagnostic::{ report_invalid_or_unsupported_base, report_invalid_return_type, report_invalid_type_checking_constant, report_invalid_type_param_order, report_named_tuple_field_with_leading_underscore, - report_namedtuple_field_without_default_after_field_with_default, report_non_subscriptable, + report_namedtuple_field_without_default_after_field_with_default, report_not_subscriptable, report_possibly_missing_attribute, report_possibly_unresolved_reference, report_rebound_typevar, report_slice_step_size_zero, report_unsupported_augmented_assignment, report_unsupported_binary_operation, report_unsupported_comparison, @@ -4372,7 +4372,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { } } CallDunderError::MethodNotAvailable => { - report_non_subscriptable( + report_not_subscriptable( &self.context, target, object_ty, @@ -12191,7 +12191,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { // Type parameter list cannot be empty, so if we reach here, `value_ty` is not a generic type. if let Some(builder) = self .context - .report_lint(&NON_SUBSCRIPTABLE, &*subscript.value) + .report_lint(&NOT_SUBSCRIPTABLE, &*subscript.value) { let mut diagnostic = builder.into_diagnostic("Cannot subscript non-generic type"); @@ -12449,7 +12449,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { _, ) if alias.generic_context(db).is_none() => { debug_assert!(alias.specialization(db).is_none()); - if let Some(builder) = self.context.report_lint(&NON_SUBSCRIPTABLE, subscript) { + if let Some(builder) = self.context.report_lint(&NOT_SUBSCRIPTABLE, subscript) { let value_type = alias.raw_value_type(db); let mut diagnostic = builder.into_diagnostic("Cannot subscript non-generic type alias"); @@ -12658,11 +12658,11 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { .as_class_literal() .is_some_and(|class| class.iter_mro(db, None).contains(&ClassBase::Generic)) { - report_non_subscriptable(context, subscript, value_ty, "__class_getitem__"); + report_not_subscriptable(context, subscript, value_ty, "__class_getitem__"); } } else { if expr_context != ExprContext::Store { - report_non_subscriptable(context, subscript, value_ty, "__getitem__"); + report_not_subscriptable(context, subscript, value_ty, "__getitem__"); } } diff --git a/crates/ty_python_semantic/src/types/infer/builder/type_expression.rs b/crates/ty_python_semantic/src/types/infer/builder/type_expression.rs index 1e186b2f0f..0d7456d89e 100644 --- a/crates/ty_python_semantic/src/types/infer/builder/type_expression.rs +++ b/crates/ty_python_semantic/src/types/infer/builder/type_expression.rs @@ -5,7 +5,7 @@ use super::{DeferredExpressionState, TypeInferenceBuilder}; use crate::FxOrderSet; use crate::semantic_index::semantic_index; use crate::types::diagnostic::{ - self, INVALID_TYPE_FORM, NON_SUBSCRIPTABLE, report_invalid_argument_number_to_special_form, + self, INVALID_TYPE_FORM, NOT_SUBSCRIPTABLE, report_invalid_argument_number_to_special_form, report_invalid_arguments_to_callable, }; use crate::types::generics::bind_typevar; @@ -921,7 +921,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> { KnownInstanceType::TypeAliasType(type_alias @ TypeAliasType::PEP695(_)) => { if type_alias.specialization(self.db()).is_some() { if let Some(builder) = - self.context.report_lint(&NON_SUBSCRIPTABLE, subscript) + self.context.report_lint(&NOT_SUBSCRIPTABLE, subscript) { let mut diagnostic = builder.into_diagnostic("Cannot subscript non-generic type alias"); @@ -951,7 +951,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> { self.infer_type_expression(slice); if let Some(builder) = - self.context.report_lint(&NON_SUBSCRIPTABLE, subscript) + self.context.report_lint(&NOT_SUBSCRIPTABLE, subscript) { let value_type = type_alias.raw_value_type(self.db()); let mut diagnostic = builder diff --git a/ty.schema.json b/ty.schema.json index e93fd1a6b9..50e0dee989 100644 --- a/ty.schema.json +++ b/ty.schema.json @@ -886,9 +886,9 @@ } ] }, - "non-subscriptable": { - "title": "detects subscripting objects that do not support subscripting", - "description": "## What it does\nChecks for subscripting objects that do not support subscripting.\n\n## Why is this bad?\nSubscripting an object that does not support it will raise a `TypeError` at runtime.\n\n## Examples\n```python\n4[1] # TypeError: 'int' object is not subscriptable\n```", + "not-iterable": { + "title": "detects iteration over an object that is not iterable", + "description": "## What it does\nChecks for objects that are not iterable but are used in a context that requires them to be.\n\n## Why is this bad?\nIterating over an object that is not iterable will raise a `TypeError` at runtime.\n\n## Examples\n\n```python\nfor i in 34: # TypeError: 'int' object is not iterable\n pass\n```", "default": "error", "oneOf": [ { @@ -896,9 +896,9 @@ } ] }, - "not-iterable": { - "title": "detects iteration over an object that is not iterable", - "description": "## What it does\nChecks for objects that are not iterable but are used in a context that requires them to be.\n\n## Why is this bad?\nIterating over an object that is not iterable will raise a `TypeError` at runtime.\n\n## Examples\n\n```python\nfor i in 34: # TypeError: 'int' object is not iterable\n pass\n```", + "not-subscriptable": { + "title": "detects subscripting objects that do not support subscripting", + "description": "## What it does\nChecks for subscripting objects that do not support subscripting.\n\n## Why is this bad?\nSubscripting an object that does not support it will raise a `TypeError` at runtime.\n\n## Examples\n```python\n4[1] # TypeError: 'int' object is not subscriptable\n```", "default": "error", "oneOf": [ {