use rustc_ast as ast;
use rustc_attr as attr;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
.collect_referenced_late_bound_regions(&poly_trait_ref)
.into_iter()
.filter_map(|br| match br {
- ty::BrNamed(_, name) if name != kw::UnderscoreLifetime => Some(GenericParamDef {
- name,
- kind: GenericParamDefKind::Lifetime { outlives: vec![] },
- }),
+ ty::BrNamed(_, name) if name != kw::UnderscoreLifetime => {
+ Some(GenericParamDef::lifetime(name))
+ }
_ => None,
})
.collect();
// FIXME: instead of storing the stringified expression, store `self` directly instead.
Constant {
type_: clean_middle_ty(constant.ty(), cx, None),
- kind: ConstantKind::TyConst { expr: constant.to_string() },
+ kind: ConstantKind::TyConst { expr: constant.to_string().into() },
}
}
p.get_bound_params()
.into_iter()
.flatten()
- .map(|param| GenericParamDef {
- name: param.0,
- kind: GenericParamDefKind::Lifetime { outlives: Vec::new() },
- })
+ .map(|param| GenericParamDef::lifetime(param.0))
.collect(),
));
}
values: types
.iter()
.enumerate()
- .map(|(i, ty)| {
- let mut name = names.get(i).map_or(kw::Empty, |ident| ident.name);
- if name.is_empty() {
- name = kw::Underscore;
- }
- Argument { name, type_: clean_ty(ty, cx), is_const: false }
+ .map(|(i, ty)| Argument {
+ type_: clean_ty(ty, cx),
+ name: names
+ .get(i)
+ .map(|ident| ident.name)
+ .filter(|ident| !ident.is_empty())
+ .unwrap_or(kw::Underscore),
+ is_const: false,
})
.collect(),
}
.iter()
.map(|t| Argument {
type_: clean_middle_ty(*t, cx, None),
- name: names.next().map_or(kw::Empty, |i| i.name),
+ name: names
+ .next()
+ .map(|i| i.name)
+ .filter(|i| !i.is_empty())
+ .unwrap_or(kw::Underscore),
is_const: false,
})
.collect(),
}
}
ty::AssocKind::Fn => {
- let generics = clean_ty_generics(
+ let sig = tcx.fn_sig(assoc_item.def_id);
+
+ let late_bound_regions = sig.bound_vars().into_iter().filter_map(|var| match var {
+ ty::BoundVariableKind::Region(ty::BrNamed(_, name))
+ if name != kw::UnderscoreLifetime =>
+ {
+ Some(GenericParamDef::lifetime(name))
+ }
+ _ => None,
+ });
+
+ let mut generics = clean_ty_generics(
cx,
tcx.generics_of(assoc_item.def_id),
tcx.explicit_predicates_of(assoc_item.def_id),
);
- let sig = tcx.fn_sig(assoc_item.def_id);
+ // FIXME: This does not place parameters in source order (late-bound ones come last)
+ generics.params.extend(late_bound_regions);
+
let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(assoc_item.def_id), sig);
if assoc_item.fn_has_self_parameter {
true
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => match &c.kind {
- ConstantKind::TyConst { expr } => expr == param.name.as_str(),
+ ConstantKind::TyConst { expr } => **expr == *param.name.as_str(),
_ => false,
},
_ => false,
..
}) = generics.params.iter_mut().find(|param| ¶m.name == arg)
{
- param_bounds.extend(mem::take(bounds));
+ param_bounds.append(bounds);
+ } else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred
+ && let Some(GenericParamDef {
+ kind: GenericParamDefKind::Lifetime { outlives: param_bounds },
+ ..
+ }) = generics.params.iter_mut().find(|param| ¶m.name == arg) {
+ param_bounds.extend(bounds.drain(..).map(|bound| match bound {
+ GenericBound::Outlives(lifetime) => lifetime,
+ _ => unreachable!(),
+ }));
} else {
where_predicates.push(pred);
}
}
};
- Array(Box::new(clean_ty(ty, cx)), length)
+ Array(Box::new(clean_ty(ty, cx)), length.into())
}
TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()),
TyKind::OpaqueDef(item_id, _, _) => {
ty::Array(ty, mut n) => {
n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
let n = print_const(cx, n);
- Array(Box::new(clean_middle_ty(ty, cx, None)), n)
+ Array(Box::new(clean_middle_ty(ty, cx, None)), n.into())
}
ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(clean_middle_ty(mt.ty, cx, None))),
ty::Ref(r, ty, mutbl) => BorrowedRef {
inline::record_extern_fqn(cx, did, ItemType::Trait);
+ // FIXME(fmease): Hide the trait-object lifetime bound if it coincides with its default
+ // to partially address #44306. Follow the rules outlined at
+ // https://doc.rust-lang.org/reference/lifetime-elision.html#default-trait-object-lifetimes
let lifetime = clean_middle_region(*reg);
let mut bounds = dids
.map(|did| {
})
.collect();
+ let late_bound_regions: FxIndexSet<_> = obj
+ .iter()
+ .flat_map(|pb| pb.bound_vars())
+ .filter_map(|br| match br {
+ ty::BoundVariableKind::Region(ty::BrNamed(_, name))
+ if name != kw::UnderscoreLifetime =>
+ {
+ Some(GenericParamDef::lifetime(name))
+ }
+ _ => None,
+ })
+ .collect();
+ let late_bound_regions = late_bound_regions.into_iter().collect();
+
let path = external_path(cx, did, false, bindings, substs);
- bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() });
+ bounds.insert(0, PolyTrait { trait_: path, generic_params: late_bound_regions });
DynTrait(bounds, lifetime)
}
BareFunctionDecl { unsafety: bare_fn.unsafety, abi: bare_fn.abi, decl, generic_params }
}
+/// This visitor is used to go through only the "top level" of a item and not enter any sub
+/// item while looking for a given `Ident` which is stored into `item` if found.
+struct OneLevelVisitor<'hir> {
+ map: rustc_middle::hir::map::Map<'hir>,
+ item: Option<&'hir hir::Item<'hir>>,
+ looking_for: Ident,
+ target_hir_id: hir::HirId,
+}
+
+impl<'hir> OneLevelVisitor<'hir> {
+ fn new(map: rustc_middle::hir::map::Map<'hir>, target_hir_id: hir::HirId) -> Self {
+ Self { map, item: None, looking_for: Ident::empty(), target_hir_id }
+ }
+
+ fn reset(&mut self, looking_for: Ident) {
+ self.looking_for = looking_for;
+ self.item = None;
+ }
+}
+
+impl<'hir> hir::intravisit::Visitor<'hir> for OneLevelVisitor<'hir> {
+ type NestedFilter = rustc_middle::hir::nested_filter::All;
+
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.map
+ }
+
+ fn visit_item(&mut self, item: &'hir hir::Item<'hir>) {
+ if self.item.is_none()
+ && item.ident == self.looking_for
+ && matches!(item.kind, hir::ItemKind::Use(_, _))
+ || item.hir_id() == self.target_hir_id
+ {
+ self.item = Some(item);
+ }
+ }
+}
+
+/// Because a `Use` item directly links to the imported item, we need to manually go through each
+/// import one by one. To do so, we go to the parent item and look for the `Ident` into it. Then,
+/// if we found the "end item" (the imported one), we stop there because we don't need its
+/// documentation. Otherwise, we repeat the same operation until we find the "end item".
+fn get_all_import_attributes<'hir>(
+ mut item: &hir::Item<'hir>,
+ tcx: TyCtxt<'hir>,
+ target_hir_id: hir::HirId,
+ attributes: &mut Vec<ast::Attribute>,
+) {
+ let hir_map = tcx.hir();
+ let mut visitor = OneLevelVisitor::new(hir_map, target_hir_id);
+ // If the item is an import and has at least a path with two parts, we go into it.
+ while let hir::ItemKind::Use(path, _) = item.kind &&
+ path.segments.len() > 1 &&
+ let hir::def::Res::Def(_, def_id) = path.segments[path.segments.len() - 2].res
+ {
+ if let Some(hir::Node::Item(parent_item)) = hir_map.get_if_local(def_id) {
+ // We add the attributes from this import into the list.
+ attributes.extend_from_slice(hir_map.attrs(item.hir_id()));
+ // We get the `Ident` we will be looking for into `item`.
+ let looking_for = path.segments[path.segments.len() - 1].ident;
+ visitor.reset(looking_for);
+ hir::intravisit::walk_item(&mut visitor, parent_item);
+ if let Some(i) = visitor.item {
+ item = i;
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+}
+
fn clean_maybe_renamed_item<'tcx>(
cx: &mut DocContext<'tcx>,
item: &hir::Item<'tcx>,
}
_ => unreachable!("not yet converted"),
};
- if let Some(import_id) = import_id {
- let (attrs, cfg) = inline::merge_attrs(
- cx,
- Some(cx.tcx.parent_module(import_id).to_def_id()),
- inline::load_attrs(cx, def_id),
- Some(inline::load_attrs(cx, cx.tcx.hir().local_def_id(import_id).to_def_id())),
- );
+
+ let mut extra_attrs = Vec::new();
+ if let Some(hir::Node::Item(use_node)) =
+ import_id.and_then(|hir_id| cx.tcx.hir().find(hir_id))
+ {
+ // We get all the various imports' attributes.
+ get_all_import_attributes(use_node, cx.tcx, item.hir_id(), &mut extra_attrs);
+ }
+
+ if !extra_attrs.is_empty() {
+ extra_attrs.extend_from_slice(inline::load_attrs(cx, def_id));
+ let attrs = Attributes::from_ast(&extra_attrs);
+ let cfg = extra_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg);
+
vec![Item::from_def_id_and_attrs_and_parts(
def_id,
Some(name),