use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;
use crate::rustc_hir as hir;
use crate::rustc_hir::attrs::lang_items::LangItem;
use crate::rustc_lint_defs::{declare_lint, declare_lint_pass};
use crate::rustc_middle::ty::Unnormalized;
use crate::rustc_lint::{LateContext, LateLintPass, LintContext};
declare_lint! {
pub MULTIPLE_SUPERTRAIT_UPCASTABLE,
Allow,
"detect when a dyn-compatible trait has multiple supertraits",
@feature_gate = multiple_supertrait_upcastable;
}
declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTABLE]);
impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
let def_id = item.owner_id.to_def_id();
if let hir::ItemKind::Trait { ident, .. } = item.kind
&& cx.tcx.is_dyn_compatible(def_id)
{
let direct_super_traits_iter = cx
.tcx
.explicit_super_clauses_of(def_id)
.iter_identity_copied()
.map(Unnormalized::skip_norm_wip)
.filter_map(|(clause, _)| clause.as_trait_clause())
.filter(|pred| !cx.tcx.is_lang_item(pred.def_id(), LangItem::MetaSized))
.filter(|pred| !cx.tcx.is_default_trait(pred.def_id()));
if direct_super_traits_iter.count() > 1 {
cx.emit_span_lint(
MULTIPLE_SUPERTRAIT_UPCASTABLE,
cx.tcx.def_span(def_id),
crate::rustc_lint::diagnostics::MultipleSupertraitUpcastable { ident },
);
}
}
}
}