Use Ancestory to check default fn in const impl instead of comparing idents
This commit is contained in:
parent
6ae8912a3e
commit
de940fc725
1 changed files with 25 additions and 17 deletions
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue