1
Fork 0

Use Ancestory to check default fn in const impl instead of comparing idents

This commit is contained in:
Gary Guo 2021-10-02 19:02:22 +01:00
parent 6ae8912a3e
commit de940fc725

View file

@ -8,7 +8,6 @@
//! through, but errors for structured control flow in a `const` should be emitted here. //! through, but errors for structured control flow in a `const` should be emitted here.
use rustc_attr as attr; use rustc_attr as attr;
use rustc_data_structures::stable_set::FxHashSet;
use rustc_errors::struct_span_err; use rustc_errors::struct_span_err;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LocalDefId;
@ -83,32 +82,41 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<
let _: Option<_> = try { let _: Option<_> = try {
if let hir::ItemKind::Impl(ref imp) = item.kind { if let hir::ItemKind::Impl(ref imp) = item.kind {
if let hir::Constness::Const = imp.constness { if let hir::Constness::Const = imp.constness {
let did = imp.of_trait.as_ref()?.trait_def_id()?; let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?;
let mut to_implement = FxHashSet::default(); let ancestors = self
.tcx
.trait_def(trait_def_id)
.ancestors(self.tcx, item.def_id.to_def_id())
.ok()?;
let mut to_implement = Vec::new();
for did in self.tcx.associated_item_def_ids(did) { for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order()
{
if let ty::AssocItem { if let ty::AssocItem {
kind: ty::AssocKind::Fn, ident, defaultness, .. kind: ty::AssocKind::Fn, ident, defaultness, ..
} = self.tcx.associated_item(*did) } = trait_item
{ {
// we can ignore functions that do not have default bodies: // we can ignore functions that do not have default bodies:
// if those are unimplemented it will be catched by typeck. // if those are unimplemented it will be catched by typeck.
if defaultness.has_value() if !defaultness.has_value()
&& !self.tcx.has_attr(*did, sym::default_method_body_is_const) || self
.tcx
.has_attr(trait_item.def_id, sym::default_method_body_is_const)
{ {
to_implement.insert(ident); continue;
}
let is_implemented = ancestors
.leaf_def(self.tcx, trait_item.ident, trait_item.kind)
.map(|node_item| !node_item.defining_node.is_from_trait())
.unwrap_or(false);
if !is_implemented {
to_implement.push(ident.to_string());
} }
} }
} }
for it in imp
.items
.iter()
.filter(|it| matches!(it.kind, hir::AssocItemKind::Fn { .. }))
{
to_implement.remove(&it.ident);
}
// all nonconst trait functions (not marked with #[default_method_body_is_const]) // all nonconst trait functions (not marked with #[default_method_body_is_const])
// must be implemented // must be implemented
if !to_implement.is_empty() { if !to_implement.is_empty() {
@ -118,7 +126,7 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<
item.span, item.span,
"const trait implementations may not use non-const default functions", "const trait implementations may not use non-const default functions",
) )
.note(&format!("`{}` not implemented", to_implement.into_iter().map(|id| id.to_string()).collect::<Vec<_>>().join("`, `"))) .note(&format!("`{}` not implemented", to_implement.join("`, `")))
.emit(); .emit();
} }
} }