diff --git a/crates/ty/tests/cli/exit_code.rs b/crates/ty/tests/cli/exit_code.rs index 5aceafbbbc..7c63564ef1 100644 --- a/crates/ty/tests/cli/exit_code.rs +++ b/crates/ty/tests/cli/exit_code.rs @@ -153,7 +153,7 @@ fn both_warnings_and_errors() -> anyhow::Result<()> { "#, )?; - assert_cmd_snapshot!(case.command().arg("--warn").arg("unresolved-reference"), @r###" + assert_cmd_snapshot!(case.command().arg("--warn").arg("unresolved-reference"), @r" success: false exit_code: 1 ----- stdout ----- @@ -171,14 +171,14 @@ fn both_warnings_and_errors() -> anyhow::Result<()> { | 2 | print(x) # [unresolved-reference] 3 | print(4[1]) # [non-subscriptable] - | ^ + | ^^^^ | info: rule `non-subscriptable` is enabled by default Found 2 diagnostics ----- stderr ----- - "###); + "); Ok(()) } @@ -193,7 +193,7 @@ fn both_warnings_and_errors_and_error_on_warning_is_true() -> anyhow::Result<()> "###, )?; - assert_cmd_snapshot!(case.command().arg("--warn").arg("unresolved-reference").arg("--error-on-warning"), @r###" + assert_cmd_snapshot!(case.command().arg("--warn").arg("unresolved-reference").arg("--error-on-warning"), @r" success: false exit_code: 1 ----- stdout ----- @@ -211,14 +211,14 @@ fn both_warnings_and_errors_and_error_on_warning_is_true() -> anyhow::Result<()> | 2 | print(x) # [unresolved-reference] 3 | print(4[1]) # [non-subscriptable] - | ^ + | ^^^^ | info: rule `non-subscriptable` is enabled by default Found 2 diagnostics ----- stderr ----- - "###); + "); Ok(()) } @@ -233,7 +233,7 @@ fn exit_zero_is_true() -> anyhow::Result<()> { "#, )?; - assert_cmd_snapshot!(case.command().arg("--exit-zero").arg("--warn").arg("unresolved-reference"), @r###" + assert_cmd_snapshot!(case.command().arg("--exit-zero").arg("--warn").arg("unresolved-reference"), @r" success: true exit_code: 0 ----- stdout ----- @@ -251,14 +251,14 @@ fn exit_zero_is_true() -> anyhow::Result<()> { | 2 | print(x) # [unresolved-reference] 3 | print(4[1]) # [non-subscriptable] - | ^ + | ^^^^ | info: rule `non-subscriptable` is enabled by default Found 2 diagnostics ----- stderr ----- - "###); + "); Ok(()) } diff --git a/crates/ty/tests/cli/main.rs b/crates/ty/tests/cli/main.rs index 446ba86611..0edbc1c414 100644 --- a/crates/ty/tests/cli/main.rs +++ b/crates/ty/tests/cli/main.rs @@ -617,7 +617,7 @@ fn gitlab_diagnostics() -> anyhow::Result<()> { let _s = settings.bind_to_scope(); assert_cmd_snapshot!(case.command().arg("--output-format=gitlab").arg("--warn").arg("unresolved-reference") - .env("CI_PROJECT_DIR", case.project_dir), @r###" + .env("CI_PROJECT_DIR", case.project_dir), @r#" success: false exit_code: 1 ----- stdout ----- @@ -655,14 +655,14 @@ fn gitlab_diagnostics() -> anyhow::Result<()> { }, "end": { "line": 3, - "column": 8 + "column": 11 } } } } ] ----- stderr ----- - "###); + "#); Ok(()) } @@ -677,15 +677,15 @@ fn github_diagnostics() -> anyhow::Result<()> { "#, )?; - assert_cmd_snapshot!(case.command().arg("--output-format=github").arg("--warn").arg("unresolved-reference"), @r###" + assert_cmd_snapshot!(case.command().arg("--output-format=github").arg("--warn").arg("unresolved-reference"), @r" success: false 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=8::test.py:3:7: non-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method + ::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 ----- stderr ----- - "###); + "); Ok(()) } 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 new file mode 100644 index 0000000000..cf32516a0f --- /dev/null +++ b/crates/ty_python_semantic/resources/mdtest/snapshots/instance.md_-_Instance_subscript_-_`__getitem__`_unboun…_(b1b0f9ed2b7302b2).snap @@ -0,0 +1,33 @@ +--- +source: crates/ty_test/src/lib.rs +expression: snapshot +--- +--- +mdtest name: instance.md - Instance subscript - `__getitem__` unbound +mdtest path: crates/ty_python_semantic/resources/mdtest/subscript/instance.md +--- + +# Python source files + +## mdtest_snippet.py + +``` +1 | class NotSubscriptable: ... +2 | +3 | a = NotSubscriptable()[0] # error: [non-subscriptable] +``` + +# Diagnostics + +``` +error[non-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] + | ^^^^^^^^^^^^^^^^^^^^^ + | +info: rule `non-subscriptable` is enabled by default + +``` diff --git a/crates/ty_python_semantic/resources/mdtest/subscript/instance.md b/crates/ty_python_semantic/resources/mdtest/subscript/instance.md index de96b7ac6c..2cb9d9bb01 100644 --- a/crates/ty_python_semantic/resources/mdtest/subscript/instance.md +++ b/crates/ty_python_semantic/resources/mdtest/subscript/instance.md @@ -2,10 +2,12 @@ ## `__getitem__` unbound + + ```py class NotSubscriptable: ... -a = NotSubscriptable()[0] # error: "Cannot subscript object of type `NotSubscriptable` with no `__getitem__` method" +a = NotSubscriptable()[0] # error: [non-subscriptable] ``` ## `__getitem__` not callable diff --git a/crates/ty_python_semantic/src/types/diagnostic.rs b/crates/ty_python_semantic/src/types/diagnostic.rs index bdbc1feb9f..3e847be1db 100644 --- a/crates/ty_python_semantic/src/types/diagnostic.rs +++ b/crates/ty_python_semantic/src/types/diagnostic.rs @@ -2034,7 +2034,7 @@ 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( context: &InferContext, - node: AnyNodeRef, + node: &ast::ExprSubscript, non_subscriptable_ty: Type, method: &str, ) { diff --git a/crates/ty_python_semantic/src/types/infer/builder.rs b/crates/ty_python_semantic/src/types/infer/builder.rs index 01bb887a75..b95b86db09 100644 --- a/crates/ty_python_semantic/src/types/infer/builder.rs +++ b/crates/ty_python_semantic/src/types/infer/builder.rs @@ -11369,11 +11369,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, value_node.into(), value_ty, "__class_getitem__"); + report_non_subscriptable(context, subscript, value_ty, "__class_getitem__"); } } else { if expr_context != ExprContext::Store { - report_non_subscriptable(context, value_node.into(), value_ty, "__getitem__"); + report_non_subscriptable(context, subscript, value_ty, "__getitem__"); } }