Repository: astral-sh/ruff
File: crates/ty_python_semantic/src/types/infer/builder.rs (Rust)

Code before:
                                            self.context.report_lint(&CALL_NON_CALLABLE, target)
                                    {
                                        let mut diagnostic = builder.into_diagnostic(format_args!(
                                            "Method `__setitem__` of type `{}` may not be callable on object of type `{}`",
                                            bindings.callable_type().display(db),
                                            object_ty.display(db),
                                        ));
                                        attach_original_type_info(&mut diagnostic);
                                    }
                                }
                            }
                            false
                        }
                        CallDunderError::MethodNotAvailable => {
                            if emit_diagnostic
                                && let Some(builder) =
                                    self.context.report_lint(&INVALID_ASSIGNMENT, target)
                            {
                                let mut diagnostic = builder.into_diagnostic(format_args!(
                                    "Cannot assign to a subscript on an object of type `{}`",
                                    object_ty.display(db),
                                ));
                                attach_original_type_info(&mut diagnostic);

                                // Use `KnownClass` as a crude proxy for checking if this is not a user-defined class. Otherwise,
                                // we end up suggesting things like "`None` may be missing a `__setitem__` method."
                                if object_ty
                                    .as_nominal_instance()
                                    .is_none_or(|instance| instance.class(db).known(db).is_none())
                                {
                                    diagnostic.info(format_args!(
                                        "`{}` may be missing a `__setitem__` method.",
                                        object_ty.display(db),
                                    ));
                                }
                            }
                            false
                        }
                    },
                }
            }
        }
    }

    /// Make sure that the attribute assignment `obj.attribute = value` is valid.
    ///
    /// `target` is the node for the left-hand side, `object_ty` is the type of `obj`, `attribute` is
    /// the name of the attribute being assigned, and `value_ty` is the type of the right-hand side of
    /// the assignment. If the assignment is invalid, emit diagnostics.
    fn validate_attribute_assignment(
        &mut self,

Review comment (suggestion):
I don't think saying "`None` may be missing a `__setitem__` method." would actually be the worst thing -- I wondered why it wasn't there when reading the tests. It is in fact the case that the reason for the diagnostic is that `None` has no `__setitem__` method! But I'm also not opposed to what you do here.

Code after:
                                            self.context.report_lint(&CALL_NON_CALLABLE, target)
                                    {
                                        let mut diagnostic = builder.into_diagnostic(format_args!(
                                            "Method `__setitem__` of type `{}` may not be callable on object of type `{}`",
                                            bindings.callable_type().display(db),
                                            object_ty.display(db),
                                        ));
                                        attach_original_type_info(&mut diagnostic);
                                    }
                                }
                            }
                            false
                        }
                        CallDunderError::MethodNotAvailable => {
                            if emit_diagnostic
                                && let Some(builder) =
                                    self.context.report_lint(&INVALID_ASSIGNMENT, target)
                            {
                                let mut diagnostic = builder.into_diagnostic(format_args!(
                                    "Cannot assign to a subscript on an object of type `{}`",
                                    object_ty.display(db),
                                ));
                                attach_original_type_info(&mut diagnostic);

                                // Use `KnownClass` as a crude proxy for checking if this is not a user-defined class. Otherwise,
                                // we end up suggesting things like "Consider adding a `__setitem__` method to `None`".
                                if object_ty
                                    .as_nominal_instance()
                                    .is_some_and(|instance| instance.class(db).known(db).is_some())
                                {
                                    diagnostic.info(format_args!(
                                        "`{}` does not have a `__setitem__` method.",
                                        object_ty.display(db),
                                    ));
                                } else {
                                    diagnostic.help(format_args!(
                                        "Consider adding a `__setitem__` method to `{}`.",
                                        object_ty.display(db),
                                    ));
                                }
                            }
                            false
                        }
                    },
                }
            }
        }
    }

    /// Make sure that the attribute assignment `obj.attribute = value` is valid.
    ///