2018-03-10 05:44:33 -06:00
|
|
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2018-03-14 08:45:30 -05:00
|
|
|
use rustc::hir::{self, ImplPolarity};
|
|
|
|
use rustc::hir::def_id::DefId;
|
|
|
|
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
|
2018-04-09 02:38:00 -05:00
|
|
|
use rustc::ty::{self, Slice, TyCtxt};
|
2018-03-20 10:13:44 -05:00
|
|
|
use rustc::ty::subst::Substs;
|
2018-04-09 02:38:00 -05:00
|
|
|
use rustc::traits::{WhereClauseAtom, PolyDomainGoal, DomainGoal, ProgramClause, Clause, Goal};
|
2018-03-10 05:44:33 -06:00
|
|
|
use syntax::ast;
|
2018-03-14 08:45:30 -05:00
|
|
|
use rustc_data_structures::sync::Lrc;
|
2018-03-10 05:44:33 -06:00
|
|
|
|
2018-04-09 02:38:00 -05:00
|
|
|
use std::iter;
|
|
|
|
|
2018-03-10 05:44:33 -06:00
|
|
|
trait Lower<T> {
|
2018-03-14 09:19:17 -05:00
|
|
|
/// Lower a rustc construction (e.g. `ty::TraitPredicate`) to a chalk-like type.
|
2018-03-10 05:44:33 -06:00
|
|
|
fn lower(&self) -> T;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T, U> Lower<Vec<U>> for Vec<T> where T: Lower<U> {
|
|
|
|
fn lower(&self) -> Vec<U> {
|
|
|
|
self.iter().map(|item| item.lower()).collect()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-14 07:38:03 -05:00
|
|
|
impl<'tcx> Lower<WhereClauseAtom<'tcx>> for ty::TraitPredicate<'tcx> {
|
2018-03-10 05:44:33 -06:00
|
|
|
fn lower(&self) -> WhereClauseAtom<'tcx> {
|
|
|
|
WhereClauseAtom::Implemented(*self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-14 07:38:03 -05:00
|
|
|
impl<'tcx> Lower<WhereClauseAtom<'tcx>> for ty::ProjectionPredicate<'tcx> {
|
2018-03-10 05:44:33 -06:00
|
|
|
fn lower(&self) -> WhereClauseAtom<'tcx> {
|
|
|
|
WhereClauseAtom::ProjectionEq(*self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx, T> Lower<DomainGoal<'tcx>> for T where T: Lower<WhereClauseAtom<'tcx>> {
|
|
|
|
fn lower(&self) -> DomainGoal<'tcx> {
|
|
|
|
DomainGoal::Holds(self.lower())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-14 07:38:03 -05:00
|
|
|
impl<'tcx> Lower<DomainGoal<'tcx>> for ty::RegionOutlivesPredicate<'tcx> {
|
2018-03-10 05:44:33 -06:00
|
|
|
fn lower(&self) -> DomainGoal<'tcx> {
|
2018-03-14 07:38:03 -05:00
|
|
|
DomainGoal::RegionOutlives(*self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> Lower<DomainGoal<'tcx>> for ty::TypeOutlivesPredicate<'tcx> {
|
|
|
|
fn lower(&self) -> DomainGoal<'tcx> {
|
|
|
|
DomainGoal::TypeOutlives(*self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-14 09:19:17 -05:00
|
|
|
/// `ty::Binder` is used for wrapping a rustc construction possibly containing generic
|
|
|
|
/// lifetimes, e.g. `for<'a> T: Fn(&'a i32)`. Instead of representing higher-ranked things
|
|
|
|
/// in that leaf-form (i.e. `Holds(Implemented(Binder<TraitPredicate>))` in the previous
|
2018-03-28 07:13:08 -05:00
|
|
|
/// example), we model them with quantified domain goals, e.g. as for the previous example:
|
2018-03-14 09:19:17 -05:00
|
|
|
/// `forall<'a> { T: Fn(&'a i32) }` which corresponds to something like
|
|
|
|
/// `Binder<Holds(Implemented(TraitPredicate))>`.
|
2018-03-28 07:13:08 -05:00
|
|
|
impl<'tcx, T> Lower<PolyDomainGoal<'tcx>> for ty::Binder<T>
|
|
|
|
where T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx>
|
2018-03-14 07:38:03 -05:00
|
|
|
{
|
2018-03-28 07:13:08 -05:00
|
|
|
fn lower(&self) -> PolyDomainGoal<'tcx> {
|
|
|
|
self.map_bound_ref(|p| p.lower())
|
2018-03-14 07:38:03 -05:00
|
|
|
}
|
|
|
|
}
|
2018-03-10 05:44:33 -06:00
|
|
|
|
2018-03-28 07:13:08 -05:00
|
|
|
impl<'tcx> Lower<PolyDomainGoal<'tcx>> for ty::Predicate<'tcx> {
|
|
|
|
fn lower(&self) -> PolyDomainGoal<'tcx> {
|
2018-03-14 08:45:30 -05:00
|
|
|
use rustc::ty::Predicate::*;
|
2018-03-14 07:38:03 -05:00
|
|
|
|
|
|
|
match self {
|
2018-03-10 05:44:33 -06:00
|
|
|
Trait(predicate) => predicate.lower(),
|
2018-03-14 07:38:03 -05:00
|
|
|
RegionOutlives(predicate) => predicate.lower(),
|
|
|
|
TypeOutlives(predicate) => predicate.lower(),
|
2018-03-10 05:44:33 -06:00
|
|
|
Projection(predicate) => predicate.lower(),
|
2018-03-28 07:13:08 -05:00
|
|
|
WellFormed(ty) => ty::Binder::dummy(DomainGoal::WellFormedTy(*ty)),
|
2018-03-10 05:44:33 -06:00
|
|
|
ObjectSafe(..) |
|
|
|
|
ClosureKind(..) |
|
|
|
|
Subtype(..) |
|
|
|
|
ConstEvaluatable(..) => unimplemented!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-26 23:03:50 -05:00
|
|
|
/// Transforms an existing goal into a FromEnv goal.
|
|
|
|
///
|
|
|
|
/// Used for lowered where clauses (see rustc guide).
|
|
|
|
trait IntoFromEnvGoal {
|
|
|
|
fn into_from_env_goal(self) -> Self;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> IntoFromEnvGoal for DomainGoal<'tcx> {
|
|
|
|
fn into_from_env_goal(self) -> DomainGoal<'tcx> {
|
|
|
|
use self::DomainGoal::*;
|
|
|
|
match self {
|
|
|
|
Holds(wc_atom) => FromEnv(wc_atom),
|
|
|
|
WellFormed(..) |
|
|
|
|
FromEnv(..) |
|
|
|
|
WellFormedTy(..) |
|
|
|
|
FromEnvTy(..) |
|
2018-04-11 07:27:00 -05:00
|
|
|
Normalize(..) |
|
2018-03-26 23:03:50 -05:00
|
|
|
RegionOutlives(..) |
|
|
|
|
TypeOutlives(..) => self,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-14 08:45:30 -05:00
|
|
|
crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
|
2018-04-09 02:38:00 -05:00
|
|
|
-> Lrc<&'tcx Slice<Clause<'tcx>>>
|
2018-03-10 05:44:33 -06:00
|
|
|
{
|
|
|
|
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
|
2018-04-03 10:53:13 -05:00
|
|
|
let node = tcx.hir.find(node_id).unwrap();
|
|
|
|
match node {
|
|
|
|
hir::map::Node::NodeItem(item) => match item.node {
|
|
|
|
hir::ItemTrait(..) => program_clauses_for_trait(tcx, def_id),
|
|
|
|
hir::ItemImpl(..) => program_clauses_for_impl(tcx, def_id),
|
|
|
|
_ => Lrc::new(vec![]),
|
|
|
|
}
|
|
|
|
hir::map::Node::NodeImplItem(item) => {
|
|
|
|
if let hir::ImplItemKind::Type(..) = item.node {
|
2018-04-06 19:04:28 -05:00
|
|
|
program_clauses_for_associated_type_value(tcx, def_id)
|
2018-04-03 10:53:13 -05:00
|
|
|
} else {
|
|
|
|
Lrc::new(vec![])
|
|
|
|
}
|
|
|
|
},
|
2018-03-14 09:19:17 -05:00
|
|
|
|
|
|
|
// FIXME: other constructions e.g. traits, associated types...
|
2018-04-09 02:38:00 -05:00
|
|
|
_ => Lrc::new(tcx.mk_clauses(iter::empty::<Clause>())),
|
2018-03-10 05:44:33 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-20 10:13:44 -05:00
|
|
|
fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
|
2018-04-09 02:38:00 -05:00
|
|
|
-> Lrc<&'tcx Slice<Clause<'tcx>>>
|
2018-03-20 10:13:44 -05:00
|
|
|
{
|
|
|
|
// `trait Trait<P1..Pn> where WC { .. } // P0 == Self`
|
2018-03-26 23:03:50 -05:00
|
|
|
|
|
|
|
// Rule Implemented-From-Env (see rustc guide)
|
2018-03-20 10:13:44 -05:00
|
|
|
//
|
|
|
|
// ```
|
|
|
|
// forall<Self, P1..Pn> {
|
|
|
|
// Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)
|
|
|
|
// }
|
|
|
|
// ```
|
|
|
|
|
|
|
|
// `Self: Trait<P1..Pn>`
|
|
|
|
let trait_pred = ty::TraitPredicate {
|
|
|
|
trait_ref: ty::TraitRef {
|
|
|
|
def_id,
|
|
|
|
substs: Substs::identity_for_item(tcx, def_id)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// `FromEnv(Self: Trait<P1..Pn>)`
|
2018-04-09 02:38:00 -05:00
|
|
|
let from_env = Goal::from(DomainGoal::FromEnv(trait_pred.lower()));
|
2018-03-20 10:13:44 -05:00
|
|
|
// `Implemented(Self: Trait<P1..Pn>)`
|
|
|
|
let impl_trait = DomainGoal::Holds(WhereClauseAtom::Implemented(trait_pred));
|
|
|
|
|
|
|
|
// `Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)`
|
2018-03-26 23:03:50 -05:00
|
|
|
let implemented_from_env = ProgramClause {
|
2018-03-28 07:13:08 -05:00
|
|
|
goal: impl_trait,
|
2018-04-09 02:38:00 -05:00
|
|
|
hypotheses: tcx.mk_goals(iter::once(from_env)),
|
2018-03-28 07:13:08 -05:00
|
|
|
};
|
2018-04-09 02:38:00 -05:00
|
|
|
let clauses = iter::once(
|
2018-03-26 23:03:50 -05:00
|
|
|
Clause::ForAll(ty::Binder::dummy(implemented_from_env))
|
2018-04-09 02:38:00 -05:00
|
|
|
);
|
2018-03-26 23:03:50 -05:00
|
|
|
|
|
|
|
// Rule Implied-Bound-From-Trait
|
|
|
|
//
|
|
|
|
// For each where clause WC:
|
|
|
|
// ```
|
|
|
|
// forall<Self, P1..Pn> {
|
|
|
|
// FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn)
|
|
|
|
// }
|
|
|
|
// ```
|
|
|
|
|
|
|
|
// `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`, for each where clause WC
|
|
|
|
// FIXME: Remove the [1..] slice; this is a hack because the query
|
|
|
|
// predicates_of currently includes the trait itself (`Self: Trait<P1..Pn>`).
|
|
|
|
let where_clauses = &tcx.predicates_of(def_id).predicates;
|
|
|
|
let implied_bound_clauses =
|
|
|
|
where_clauses[1..].into_iter()
|
2018-04-09 02:38:00 -05:00
|
|
|
.map(|wc| implied_bound_from_trait(tcx, trait_pred, wc));
|
2018-03-26 23:03:50 -05:00
|
|
|
|
2018-04-09 02:38:00 -05:00
|
|
|
Lrc::new(tcx.mk_clauses(clauses.chain(implied_bound_clauses)))
|
2018-03-26 23:03:50 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// For a given `where_clause`, returns a clause `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`.
|
2018-04-09 02:38:00 -05:00
|
|
|
fn implied_bound_from_trait<'a, 'tcx>(
|
|
|
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
2018-03-26 23:03:50 -05:00
|
|
|
trait_pred: ty::TraitPredicate<'tcx>,
|
|
|
|
where_clause: &ty::Predicate<'tcx>,
|
|
|
|
) -> Clause<'tcx> {
|
|
|
|
// `FromEnv(Self: Trait<P1..Pn>)`
|
|
|
|
let impl_trait = DomainGoal::FromEnv(WhereClauseAtom::Implemented(trait_pred));
|
|
|
|
|
|
|
|
// `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`
|
|
|
|
Clause::ForAll(
|
|
|
|
where_clause.lower().map_bound(|goal| ProgramClause {
|
|
|
|
goal: goal.into_from_env_goal(),
|
2018-04-09 02:38:00 -05:00
|
|
|
hypotheses: tcx.mk_goals(iter::once(Goal::from(impl_trait))),
|
2018-03-26 23:03:50 -05:00
|
|
|
})
|
|
|
|
)
|
2018-03-20 10:13:44 -05:00
|
|
|
}
|
|
|
|
|
2018-03-10 05:44:33 -06:00
|
|
|
fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
|
2018-04-09 02:38:00 -05:00
|
|
|
-> Lrc<&'tcx Slice<Clause<'tcx>>>
|
2018-03-10 05:44:33 -06:00
|
|
|
{
|
|
|
|
if let ImplPolarity::Negative = tcx.impl_polarity(def_id) {
|
2018-04-09 02:38:00 -05:00
|
|
|
return Lrc::new(tcx.mk_clauses(iter::empty::<Clause>()));
|
2018-03-10 05:44:33 -06:00
|
|
|
}
|
2018-03-15 17:20:06 -05:00
|
|
|
|
2018-03-20 10:11:26 -05:00
|
|
|
// Rule Implemented-From-Impl (see rustc guide)
|
2018-03-15 13:27:00 -05:00
|
|
|
//
|
2018-03-20 10:11:26 -05:00
|
|
|
// `impl<P0..Pn> Trait<A1..An> for A0 where WC { .. }`
|
|
|
|
//
|
|
|
|
// ```
|
|
|
|
// forall<P0..Pn> {
|
|
|
|
// Implemented(A0: Trait<A1..An>) :- WC
|
|
|
|
// }
|
|
|
|
// ```
|
2018-03-10 05:44:33 -06:00
|
|
|
|
|
|
|
let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
|
2018-03-20 10:11:26 -05:00
|
|
|
// `Implemented(A0: Trait<A1..An>)`
|
|
|
|
let trait_pred = ty::TraitPredicate { trait_ref }.lower();
|
|
|
|
// `WC`
|
2018-03-10 05:44:33 -06:00
|
|
|
let where_clauses = tcx.predicates_of(def_id).predicates.lower();
|
|
|
|
|
2018-03-20 10:11:26 -05:00
|
|
|
// `Implemented(A0: Trait<A1..An>) :- WC`
|
2018-03-28 07:13:08 -05:00
|
|
|
let clause = ProgramClause {
|
|
|
|
goal: trait_pred,
|
2018-04-09 02:38:00 -05:00
|
|
|
hypotheses: tcx.mk_goals(
|
|
|
|
where_clauses.into_iter().map(|wc| Goal::from_poly_domain_goal(wc, tcx))
|
|
|
|
)
|
2018-03-28 07:13:08 -05:00
|
|
|
};
|
2018-04-09 02:38:00 -05:00
|
|
|
Lrc::new(tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause)))))
|
2018-03-10 05:44:33 -06:00
|
|
|
}
|
|
|
|
|
2018-04-06 19:04:28 -05:00
|
|
|
pub fn program_clauses_for_associated_type_value<'a, 'tcx>(
|
|
|
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
|
|
item_id: DefId,
|
|
|
|
) -> Lrc<Vec<Clause<'tcx>>> {
|
2018-04-03 10:53:13 -05:00
|
|
|
// Rule Normalize-From-Impl (see rustc guide)
|
|
|
|
//
|
|
|
|
// ```impl<P0..Pn> Trait<A1..An> for A0
|
|
|
|
// where WC
|
|
|
|
// {
|
|
|
|
// type AssocType<Pn+1..Pm> where WC1 = T;
|
|
|
|
// }```
|
|
|
|
//
|
|
|
|
// ```
|
|
|
|
// forall<P0..Pm> {
|
|
|
|
// forall<Pn+1..Pm> {
|
|
|
|
// Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T) :-
|
|
|
|
// WC && WC1
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// ```
|
|
|
|
|
|
|
|
let item = tcx.associated_item(item_id);
|
|
|
|
debug_assert_eq!(item.kind, ty::AssociatedKind::Type);
|
|
|
|
let impl_id = if let ty::AssociatedItemContainer::ImplContainer(impl_id) = item.container {
|
|
|
|
impl_id
|
|
|
|
} else {
|
|
|
|
bug!()
|
|
|
|
};
|
|
|
|
// `A0 as Trait<A1..An>`
|
|
|
|
let trait_ref = tcx.impl_trait_ref(impl_id).unwrap();
|
|
|
|
// `T`
|
|
|
|
let ty = tcx.type_of(item_id);
|
|
|
|
// `WC`
|
|
|
|
let impl_where_clauses = tcx.predicates_of(impl_id).predicates.lower();
|
|
|
|
// `WC1`
|
|
|
|
let item_where_clauses = tcx.predicates_of(item_id).predicates.lower();
|
|
|
|
// `WC && WC1`
|
|
|
|
let mut where_clauses = vec![];
|
|
|
|
where_clauses.extend(impl_where_clauses);
|
|
|
|
where_clauses.extend(item_where_clauses);
|
|
|
|
// `<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm>`
|
|
|
|
let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.name);
|
|
|
|
// `Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T)`
|
|
|
|
let normalize_goal = DomainGoal::Normalize(ty::ProjectionPredicate { projection_ty, ty });
|
|
|
|
// `Normalize(... -> T) :- WC && WC1`
|
2018-04-11 07:27:00 -05:00
|
|
|
let clause = ProgramClause {
|
|
|
|
goal: normalize_goal,
|
|
|
|
hypotheses: where_clauses.into_iter().map(|wc| wc.into()).collect(),
|
|
|
|
};
|
|
|
|
Lrc::new(vec![Clause::ForAll(ty::Binder::dummy(clause))])
|
2018-04-03 10:53:13 -05:00
|
|
|
}
|
|
|
|
|
2018-03-10 05:44:33 -06:00
|
|
|
pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
|
|
|
if !tcx.features().rustc_attrs {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut visitor = ClauseDumper { tcx };
|
|
|
|
tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ClauseDumper<'a, 'tcx: 'a> {
|
|
|
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
|
|
}
|
|
|
|
|
2018-03-28 07:13:08 -05:00
|
|
|
impl<'a, 'tcx> ClauseDumper<'a, 'tcx > {
|
2018-03-10 05:44:33 -06:00
|
|
|
fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) {
|
|
|
|
let def_id = self.tcx.hir.local_def_id(node_id);
|
|
|
|
for attr in attrs {
|
|
|
|
if attr.check_name("rustc_dump_program_clauses") {
|
|
|
|
let clauses = self.tcx.program_clauses_for(def_id);
|
2018-04-09 02:38:00 -05:00
|
|
|
for clause in *clauses {
|
2018-04-02 15:25:22 -05:00
|
|
|
// Skip the top-level binder for a less verbose output
|
2018-03-28 07:13:08 -05:00
|
|
|
let program_clause = match clause {
|
|
|
|
Clause::Implies(program_clause) => program_clause,
|
|
|
|
Clause::ForAll(program_clause) => program_clause.skip_binder(),
|
|
|
|
};
|
|
|
|
self.tcx.sess.struct_span_err(attr.span, &format!("{}", program_clause)).emit();
|
2018-03-10 05:44:33 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, 'tcx> Visitor<'tcx> for ClauseDumper<'a, 'tcx> {
|
|
|
|
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
|
|
|
|
NestedVisitorMap::OnlyBodies(&self.tcx.hir)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_item(&mut self, item: &'tcx hir::Item) {
|
|
|
|
self.process_attrs(item.id, &item.attrs);
|
|
|
|
intravisit::walk_item(self, item);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
|
|
|
|
self.process_attrs(trait_item.id, &trait_item.attrs);
|
|
|
|
intravisit::walk_trait_item(self, trait_item);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
|
|
|
|
self.process_attrs(impl_item.id, &impl_item.attrs);
|
|
|
|
intravisit::walk_impl_item(self, impl_item);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
|
|
|
|
self.process_attrs(s.id, &s.attrs);
|
|
|
|
intravisit::walk_struct_field(self, s);
|
|
|
|
}
|
|
|
|
}
|