Use __class_getitem__ for more specific non-subscript errors (#13596)

This commit is contained in:
Charlie Marsh 2024-10-01 14:16:00 -04:00 committed by GitHub
parent 0a6dc8e1b8
commit 961fc98344
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1327,12 +1327,13 @@ impl<'db> TypeInferenceBuilder<'db> {
&mut self, &mut self,
node: AnyNodeRef, node: AnyNodeRef,
non_subscriptable_ty: Type<'db>, non_subscriptable_ty: Type<'db>,
method: &str,
) { ) {
self.add_diagnostic( self.add_diagnostic(
node, node,
"non-subscriptable", "non-subscriptable",
format_args!( format_args!(
"Cannot subscript object of type '{}' with no `__getitem__` method.", "Cannot subscript object of type '{}' with no `{method}` method.",
non_subscriptable_ty.display(self.db) non_subscriptable_ty.display(self.db)
), ),
); );
@ -2627,10 +2628,16 @@ impl<'db> TypeInferenceBuilder<'db> {
.call(self.db, &[slice_ty]) .call(self.db, &[slice_ty])
.unwrap_with_diagnostic(self.db, value.as_ref().into(), self); .unwrap_with_diagnostic(self.db, value.as_ref().into(), self);
} }
self.non_subscriptable_diagnostic(
(&**value).into(),
value_ty,
"__class_getitem__",
);
} else {
self.non_subscriptable_diagnostic((&**value).into(), value_ty, "__getitem__");
} }
// Otherwise, emit a diagnostic.
self.non_subscriptable_diagnostic((&**value).into(), value_ty);
Type::Unknown Type::Unknown
} }
} }
@ -6791,6 +6798,30 @@ mod tests {
Ok(()) Ok(())
} }
#[test]
fn subscript_class_getitem_unbound() -> anyhow::Result<()> {
let mut db = setup_db();
db.write_dedented(
"/src/a.py",
"
class NotSubscriptable:
pass
a = NotSubscriptable[0]
",
)?;
assert_public_ty(&db, "/src/a.py", "a", "Unknown");
assert_file_diagnostics(
&db,
"/src/a.py",
&["Cannot subscript object of type 'Literal[NotSubscriptable]' with no `__class_getitem__` method."],
);
Ok(())
}
#[test] #[test]
fn subscript_not_callable_getitem() -> anyhow::Result<()> { fn subscript_not_callable_getitem() -> anyhow::Result<()> {
let mut db = setup_db(); let mut db = setup_db();