Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TraitDef::find_map_relevant_impl #77754

Merged
merged 3 commits into from
Oct 10, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
adt_def => { cdata.get_adt_def(def_id.index, tcx) }
adt_destructor => {
let _ = cdata;
tcx.calculate_dtor(def_id, &mut |_,_| Ok(()))
tcx.calculate_dtor(def_id, |_,_| Ok(()))
}
variances_of => { tcx.arena.alloc_from_iter(cdata.get_item_variances(def_id.index)) }
associated_item_def_ids => {
Expand Down
35 changes: 35 additions & 0 deletions compiler/rustc_middle/src/ty/trait_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,41 @@ impl<'tcx> TyCtxt<'tcx> {
}
}

/// Applies function to every impl that could possibly match the self type `self_ty` and returns
/// the first non-none value.
pub fn find_map_relevant_impl<T, F: Fn(DefId) -> Option<T>>(
self,
def_id: DefId,
self_ty: Ty<'tcx>,
f: F,
) -> Option<T> {
let impls = self.trait_impls_of(def_id);

for &impl_def_id in impls.blanket_impls.iter() {
if let result @ Some(_) = f(impl_def_id) {
return result;
}
}

if let Some(simp) = fast_reject::simplify_type(self, self_ty, true) {
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
for &impl_def_id in impls {
if let result @ Some(_) = f(impl_def_id) {
return result;
}
}
}
} else {
for &impl_def_id in impls.non_blanket_impls.values().flatten() {
if let result @ Some(_) = f(impl_def_id) {
return result;
}
}
}

None
}

/// Returns an iterator containing all impls
pub fn all_impls(self, def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx {
let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(def_id);
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_middle/src/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,19 +341,19 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn calculate_dtor(
self,
adt_did: DefId,
validate: &mut dyn FnMut(Self, DefId) -> Result<(), ErrorReported>,
validate: impl Fn(Self, DefId) -> Result<(), ErrorReported>,
jyn514 marked this conversation as resolved.
Show resolved Hide resolved
) -> Option<ty::Destructor> {
let drop_trait = self.lang_items().drop_trait()?;
self.ensure().coherent_trait(drop_trait);

let mut dtor_did = None;
let ty = self.type_of(adt_did);
self.for_each_relevant_impl(drop_trait, ty, |impl_did| {
let dtor_did = self.find_map_relevant_impl(drop_trait, ty, |impl_did| {
if let Some(item) = self.associated_items(impl_did).in_definition_order().next() {
if validate(self, impl_did).is_ok() {
dtor_did = Some(item.def_id);
return Some(item.def_id);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically I'm changing the semantics here. The old code returned the last def_id, while the new one returns the first. Let me know if this is a problem.

}
}
None
});

Some(ty::Destructor { did: dtor_did? })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> {

fn is_const_item_without_destructor(&self, local: Local) -> Option<DefId> {
let def_id = self.is_const_item(local)?;
let mut any_dtor = |_tcx, _def_id| Ok(());

// We avoid linting mutation of a const item if the const's type has a
// Drop impl. The Drop logic observes the mutation which was performed.
Expand All @@ -54,7 +53,7 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> {
//
// #[const_mutation_allowed]
// pub const LOG: Log = Log { msg: "" };
match self.tcx.calculate_dtor(def_id, &mut any_dtor) {
match self.tcx.calculate_dtor(def_id, |_, _| Ok(())) {
Some(_) => None,
None => Some(def_id),
}
Expand Down
12 changes: 3 additions & 9 deletions compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1384,17 +1384,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
trait_ref: &ty::PolyTraitRef<'tcx>,
) {
let get_trait_impl = |trait_def_id| {
let mut trait_impl = None;
self.tcx.for_each_relevant_impl(
self.tcx.find_map_relevant_impl(
trait_def_id,
trait_ref.skip_binder().self_ty(),
|impl_def_id| {
if trait_impl.is_none() {
trait_impl = Some(impl_def_id);
}
},
);
trait_impl
|impl_def_id| Some(impl_def_id),
)
};
let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
let all_traits = self.tcx.all_traits(LOCAL_CRATE);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ pub fn provide(providers: &mut Providers) {
}

fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl)
tcx.calculate_dtor(def_id, dropck::check_drop_impl)
}

/// If this `DefId` is a "primary tables entry", returns
Expand Down
16 changes: 6 additions & 10 deletions src/librustdoc/passes/collect_intra_doc_links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -650,14 +650,9 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx
let ty = cx.tcx.type_of(type_);
let iter = in_scope_traits.iter().flat_map(|&trait_| {
trace!("considering explicit impl for trait {:?}", trait_);
let mut saw_impl = false;
// Look at each trait implementation to see if it's an impl for `did`
cx.tcx.for_each_relevant_impl(trait_, ty, |impl_| {
// FIXME: this is inefficient, find a way to short-circuit for_each_* so this doesn't take as long
if saw_impl {
return;
}

// Look at each trait implementation to see if it's an impl for `did`
cx.tcx.find_map_relevant_impl(trait_, ty, |impl_| {
let trait_ref = cx.tcx.impl_trait_ref(impl_).expect("this is not an inherent impl");
// Check if these are the same type.
let impl_type = trait_ref.self_ty();
Expand All @@ -668,7 +663,7 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx
type_
);
// Fast path: if this is a primitive simple `==` will work
saw_impl = impl_type == ty
let saw_impl = impl_type == ty
|| match impl_type.kind() {
// Check if these are the same def_id
ty::Adt(def, _) => {
Expand All @@ -678,8 +673,9 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx
ty::Foreign(def_id) => *def_id == type_,
_ => false,
};
});
if saw_impl { Some(trait_) } else { None }

if saw_impl { Some(trait_) } else { None }
})
});
iter.collect()
}
Expand Down