From c39521adf743bbc34fecdab788a1222418692724 Mon Sep 17 00:00:00 2001 From: Arthur Carcano Date: Fri, 22 Mar 2024 12:39:39 +0100 Subject: [PATCH 1/6] Detect and resolve amibiguities in fn parameters type names Fixes: https://github.com/rust-lang/rust/issues/122673 --- src/librustdoc/html/format.rs | 59 ++++++++++++++++++++++++++- tests/rustdoc/fn_param_ambiguities.rs | 13 ++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 tests/rustdoc/fn_param_ambiguities.rs diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 312765d3e6d03..ec52400fd046b 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -11,10 +11,12 @@ use std::borrow::Cow; use std::cell::Cell; use std::fmt::{self, Display, Write}; use std::iter::{self, once}; +use std::rc::Rc; use rustc_ast as ast; use rustc_attr::{ConstStability, StabilityLevel}; use rustc_data_structures::captures::Captures; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -1418,6 +1420,53 @@ impl clean::FnDecl { }) } + fn ambiguities<'a>( + types: impl Iterator, + ) -> FxHashMap>> { + fn inner( + ty: &clean::Type, + res_map: &mut FxHashMap>>, + conflict_map: &mut FxHashMap>>, + ) { + match ty { + clean::Type::Path { path } => { + res_map.entry(path.def_id()).or_insert_with(|| { + let last = path.last(); + conflict_map + .entry(last) + .and_modify(|b| { + b.replace(true); + }) + .or_insert_with(|| Rc::new(Cell::new(false))) + .clone() + }); + } + clean::Type::Tuple(types) => { + for ty in types { + inner(ty, res_map, conflict_map) + } + } + clean::Type::Slice(ty) + | clean::Type::Array(ty, _) + | clean::Type::RawPointer(_, ty) + | clean::Type::BorrowedRef { type_: ty, .. } => inner(ty, res_map, conflict_map), + clean::Type::QPath(_) + | clean::Type::Infer + | clean::Type::ImplTrait(_) + | clean::Type::BareFunction(_) + | clean::Type::Primitive(_) + | clean::Type::Generic(_) + | clean::Type::DynTrait(_, _) => (), + } + } + let mut res_map = FxHashMap::default(); + let mut conflict_map = FxHashMap::default(); + for ty in types { + inner(ty, &mut res_map, &mut conflict_map) + } + res_map + } + fn inner_full_print( &self, // For None, the declaration will not be line-wrapped. For Some(n), @@ -1434,6 +1483,7 @@ impl clean::FnDecl { { write!(f, "\n{}", Indent(n + 4))?; } + let ambiguities = Self::ambiguities(self.inputs.values.iter().map(|inpt| &inpt.type_)); for (i, input) in self.inputs.values.iter().enumerate() { if i > 0 { match line_wrapping_indent { @@ -1471,7 +1521,14 @@ impl clean::FnDecl { write!(f, "const ")?; } write!(f, "{}: ", input.name)?; - input.type_.print(cx).fmt(f)?; + + let use_absolute = input + .type_ + .def_id(cx.cache()) + .and_then(|did| ambiguities.get(&did)) + .map(|rcb| rcb.get()) + .unwrap_or(false); + fmt_type(&input.type_, f, use_absolute, cx)?; } } diff --git a/tests/rustdoc/fn_param_ambiguities.rs b/tests/rustdoc/fn_param_ambiguities.rs new file mode 100644 index 0000000000000..6e9f37de0ee96 --- /dev/null +++ b/tests/rustdoc/fn_param_ambiguities.rs @@ -0,0 +1,13 @@ +pub mod X { + pub enum A {} + pub enum B {} + pub enum C {} +} + +pub mod Y { + pub enum A {} + pub enum B {} +} + +// @has fn_param_ambiguities/fn.f.html //pre 'pub fn f(xa: fn_param_ambiguities::X::A, ya: fn_param_ambiguities::Y::A, yb: B, xc: C)' +pub fn f(xa: X::A, ya: Y::A, yb : Y::B, xc: X::C) {} From e695f42550e84017de6e7ffa77f9e7131738953d Mon Sep 17 00:00:00 2001 From: Arthur Carcano Date: Fri, 22 Mar 2024 17:27:55 +0100 Subject: [PATCH 2/6] wip --- src/librustdoc/html/format.rs | 268 +++++++++++++++++++++++++++------- 1 file changed, 216 insertions(+), 52 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index ec52400fd046b..bd64713ce1b9d 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -11,7 +11,6 @@ use std::borrow::Cow; use std::cell::Cell; use std::fmt::{self, Display, Write}; use std::iter::{self, once}; -use std::rc::Rc; use rustc_ast as ast; use rustc_attr::{ConstStability, StabilityLevel}; @@ -29,6 +28,7 @@ use rustc_span::{sym, Symbol}; use rustc_target::spec::abi::Abi; use itertools::Itertools; +use thin_vec::ThinVec; use crate::clean::{ self, types::ExternalLocation, utils::find_nearest_parent_module, ExternalCrate, PrimitiveType, @@ -183,6 +183,165 @@ pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>( }) } +#[derive(Clone)] +struct PathView<'a> { + path: &'a clean::Path, + suffix_len: usize, +} + +impl<'a> PathView<'a> { + fn make_longer(self) -> Self { + let Self { path, suffix_len } = self; + assert!(suffix_len < path.segments.len()); + Self { path, suffix_len: suffix_len + 1 } + } + + fn iter_from_end(&self) -> impl Iterator { + self.path.segments.iter().map(|seg| &seg.name).rev().take(self.suffix_len) + } +} + +impl<'a> Eq for PathView<'a> {} +impl<'a> PartialEq for PathView<'a> { + fn eq(&self, other: &Self) -> bool { + if self.suffix_len != other.suffix_len { + return false; + } + let self_suffix = self.iter_from_end(); + let other_suffix = self.iter_from_end(); + self_suffix.zip(other_suffix).all(|(s, o)| s.eq(o)) + } +} + +impl<'a> std::hash::Hash for PathView<'a> { + fn hash(&self, state: &mut H) { + for sym in self.iter_from_end() { + sym.hash(state) + } + } +} + +struct AmbiguityTable<'a> { + inner: FxHashMap>, +} + +impl<'a> AmbiguityTable<'a> { + fn build() -> AmbiguityTableBuilder<'a> { + AmbiguityTableBuilder { inner: FxHashMap::default() } + } +} + +enum AmbiguityTableBuilderEntry { + MapsToOne(DefId), + IsAmbiguous, +} + +struct AmbiguityTableBuilder<'a> { + inner: FxHashMap, AmbiguityTableBuilderEntry>, +} + +impl<'a> AmbiguityTableBuilder<'a> { + // Invariant: must start with length 1 path view + fn add_path_view(&mut self, p: PathView<'a>, did: DefId) { + use std::collections::hash_map::Entry::*; + // TODO: clone + match self.inner.entry(p.clone()) { + Occupied(entry) => { + let v = + std::mem::replace(entry.into_mut(), AmbiguityTableBuilderEntry::IsAmbiguous); + let p = p.make_longer(); + match v { + AmbiguityTableBuilderEntry::MapsToOne(other_did) => { + self.add_path_view(p.clone(), other_did) + } + AmbiguityTableBuilderEntry::IsAmbiguous => (), + } + self.add_path_view(p.clone(), did) + } + Vacant(entry) => { + entry.insert(AmbiguityTableBuilderEntry::MapsToOne(did)); + } + } + } + + fn add_path(&mut self, path: &'a clean::Path) { + let pv = PathView { path, suffix_len: 1 }; + self.add_path_view(pv, path.def_id()) + } + + fn add_generic_bound(&mut self, generic_bound: &'a clean::GenericBound) { + match generic_bound { + clean::GenericBound::TraitBound(poly_trait, _) => self.add_poly_trait(poly_trait), + clean::GenericBound::Outlives(_) => (), + } + } + + fn add_poly_trait(&mut self, poly_trait: &'a clean::PolyTrait) { + // TODO: also add potential bounds on trait parameters + self.add_path(&poly_trait.trait_); + for gen_param in &poly_trait.generic_params { + use clean::GenericParamDefKind::*; + match &gen_param.kind { + Type { bounds, .. } => { + for bnd in bounds { + self.add_generic_bound(bnd) + } + } + Lifetime { .. } | Const { .. } => (), + } + } + } + + fn add_type(&mut self, ty: &'a clean::Type) { + match ty { + clean::Type::Path { path } => self.add_path(path), + clean::Type::Tuple(tys) => { + for ty in tys { + self.add_type(ty) + } + } + clean::Type::RawPointer(_, ty) + | clean::Type::Slice(ty) + | clean::Type::BorrowedRef { type_: ty, .. } + | clean::Type::Array(ty, _) => self.add_type(ty), + + clean::Type::DynTrait(poly_trait, _) => { + for trai in poly_trait { + self.add_poly_trait(trai) + } + } + + clean::Type::BareFunction(bare_func_decl) => { + let clean::FnDecl { output, inputs, .. } = &bare_func_decl.decl; + self.add_type(output); + for inpt in &inputs.values { + self.add_type(&inpt.type_) + } + } + clean::Type::ImplTrait(bnds) => { + for bnd in bnds { + self.add_generic_bound(bnd) + } + } + clean::Type::Infer + | clean::Type::QPath(_) + | clean::Type::Primitive(_) + | clean::Type::Generic(_) => (), + } + } + + fn finnish(self) -> AmbiguityTable<'a> { + let mut inner = FxHashMap::default(); + for (path_view, did) in self.inner { + if let AmbiguityTableBuilderEntry::MapsToOne(did) = did { + let hopefully_none = inner.insert(did, path_view); + assert!(hopefully_none.is_none()); + } + } + AmbiguityTable { inner } + } +} + impl clean::GenericParamDef { pub(crate) fn print<'a, 'tcx: 'a>( &'a self, @@ -991,6 +1150,7 @@ fn fmt_type<'cx>( t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool, + ambiguity_table: &AmbiguityTable<'_>, cx: &'cx Context<'_>, ) -> fmt::Result { trace!("fmt_type(t = {t:?})"); @@ -1000,11 +1160,11 @@ fn fmt_type<'cx>( clean::Type::Path { ref path } => { // Paths like `T::Output` and `Self::Output` should be rendered with all segments. let did = path.def_id(); - resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, cx) + resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, ambiguity_table, cx) } clean::DynTrait(ref bounds, ref lt) => { f.write_str("dyn ")?; - tybounds(bounds, lt, cx).fmt(f) + tybounds(bounds, lt, ambiguity_table, cx).fmt(f) } clean::Infer => write!(f, "_"), clean::Primitive(clean::PrimitiveType::Never) => { @@ -1022,7 +1182,7 @@ fn fmt_type<'cx>( } else { primitive_link(f, PrimitiveType::Fn, format_args!("fn"), cx)?; } - decl.decl.print(cx).fmt(f) + decl.decl.print(ambiguity_table, cx).fmt(f) } clean::Tuple(ref typs) => match &typs[..] { &[] => primitive_link(f, PrimitiveType::Unit, format_args!("()"), cx), @@ -1031,7 +1191,7 @@ fn fmt_type<'cx>( primitive_link(f, PrimitiveType::Tuple, format_args!("({name},)"), cx) } else { write!(f, "(")?; - one.print(cx).fmt(f)?; + one.print(ambiguity_table, cx).fmt(f)?; write!(f, ",)") } } @@ -1420,52 +1580,52 @@ impl clean::FnDecl { }) } - fn ambiguities<'a>( - types: impl Iterator, - ) -> FxHashMap>> { - fn inner( - ty: &clean::Type, - res_map: &mut FxHashMap>>, - conflict_map: &mut FxHashMap>>, - ) { - match ty { - clean::Type::Path { path } => { - res_map.entry(path.def_id()).or_insert_with(|| { - let last = path.last(); - conflict_map - .entry(last) - .and_modify(|b| { - b.replace(true); - }) - .or_insert_with(|| Rc::new(Cell::new(false))) - .clone() - }); - } - clean::Type::Tuple(types) => { - for ty in types { - inner(ty, res_map, conflict_map) - } - } - clean::Type::Slice(ty) - | clean::Type::Array(ty, _) - | clean::Type::RawPointer(_, ty) - | clean::Type::BorrowedRef { type_: ty, .. } => inner(ty, res_map, conflict_map), - clean::Type::QPath(_) - | clean::Type::Infer - | clean::Type::ImplTrait(_) - | clean::Type::BareFunction(_) - | clean::Type::Primitive(_) - | clean::Type::Generic(_) - | clean::Type::DynTrait(_, _) => (), - } - } - let mut res_map = FxHashMap::default(); - let mut conflict_map = FxHashMap::default(); - for ty in types { - inner(ty, &mut res_map, &mut conflict_map) - } - res_map - } + // fn ambiguities<'a>( + // types: impl Iterator, + // ) -> FxHashMap>> { + // fn inner( + // ty: &clean::Type, + // res_map: &mut FxHashMap>>, + // conflict_map: &mut FxHashMap>>, + // ) { + // match ty { + // clean::Type::Path { path } => { + // res_map.entry(path.def_id()).or_insert_with(|| { + // let last = path.last(); + // conflict_map + // .entry(last) + // .and_modify(|b| { + // b.replace(true); + // }) + // .or_insert_with(|| Rc::new(Cell::new(false))) + // .clone() + // }); + // } + // clean::Type::Tuple(types) => { + // for ty in types { + // inner(ty, res_map, conflict_map) + // } + // } + // clean::Type::Slice(ty) + // | clean::Type::Array(ty, _) + // | clean::Type::RawPointer(_, ty) + // | clean::Type::BorrowedRef { type_: ty, .. } => inner(ty, res_map, conflict_map), + // clean::Type::QPath(_) + // | clean::Type::Infer + // | clean::Type::ImplTrait(_) + // | clean::Type::BareFunction(_) + // | clean::Type::Primitive(_) + // | clean::Type::Generic(_) + // | clean::Type::DynTrait(_, _) => (), + // } + // } + // let mut res_map = FxHashMap::default(); + // let mut conflict_map = FxHashMap::default(); + // for ty in types { + // inner(ty, &mut res_map, &mut conflict_map) + // } + // res_map + // } fn inner_full_print( &self, @@ -1483,7 +1643,11 @@ impl clean::FnDecl { { write!(f, "\n{}", Indent(n + 4))?; } - let ambiguities = Self::ambiguities(self.inputs.values.iter().map(|inpt| &inpt.type_)); + let mut ambiguity_table_builder = AmbiguityTable::build(); + for inpt in &self.inputs.values { + ambiguity_table_builder.add_type(&inpt.type_) + } + let ambiguity_table = ambiguity_table_builder.finnish(); for (i, input) in self.inputs.values.iter().enumerate() { if i > 0 { match line_wrapping_indent { From 860b40c5e7abc373ef490b0d7008b7a7b1c9f3e0 Mon Sep 17 00:00:00 2001 From: Arthur Carcano Date: Fri, 22 Mar 2024 17:57:16 +0100 Subject: [PATCH 3/6] wip2 --- src/librustdoc/html/format.rs | 94 +++++++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 27 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index bd64713ce1b9d..267e2bb021168 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -28,7 +28,6 @@ use rustc_span::{sym, Symbol}; use rustc_target::spec::abi::Abi; use itertools::Itertools; -use thin_vec::ThinVec; use crate::clean::{ self, types::ExternalLocation, utils::find_nearest_parent_module, ExternalCrate, PrimitiveType, @@ -196,7 +195,7 @@ impl<'a> PathView<'a> { Self { path, suffix_len: suffix_len + 1 } } - fn iter_from_end(&self) -> impl Iterator { + fn iter_from_end(&self) -> impl DoubleEndedIterator { self.path.segments.iter().map(|seg| &seg.name).rev().take(self.suffix_len) } } @@ -345,6 +344,7 @@ impl<'a> AmbiguityTableBuilder<'a> { impl clean::GenericParamDef { pub(crate) fn print<'a, 'tcx: 'a>( &'a self, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match &self.kind { @@ -373,14 +373,14 @@ impl clean::GenericParamDef { if let Some(ref ty) = default { f.write_str(" = ")?; - ty.print(cx).fmt(f)?; + ty.print(ambiguity_table, cx).fmt(f)?; } Ok(()) } clean::GenericParamDefKind::Const { ty, default, .. } => { write!(f, "const {}: ", self.name)?; - ty.print(cx).fmt(f)?; + ty.print(ambiguity_table, cx).fmt(f)?; if let Some(default) = default { f.write_str(" = ")?; @@ -400,6 +400,7 @@ impl clean::GenericParamDef { impl clean::Generics { pub(crate) fn print<'a, 'tcx: 'a>( &'a self, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { @@ -409,9 +410,17 @@ impl clean::Generics { } if f.alternate() { - write!(f, "<{:#}>", comma_sep(real_params.map(|g| g.print(cx)), true)) + write!( + f, + "<{:#}>", + comma_sep(real_params.map(|g| g.print(ambiguity_table, cx)), true) + ) } else { - write!(f, "<{}>", comma_sep(real_params.map(|g| g.print(cx)), true)) + write!( + f, + "<{}>", + comma_sep(real_params.map(|g| g.print(ambiguity_table, cx)), true) + ) } }) } @@ -428,6 +437,7 @@ pub(crate) enum Ending { /// * Whether the where-clause needs to add a comma and newline after the last bound. pub(crate) fn print_where_clause<'a, 'tcx: 'a>( gens: &'a clean::Generics, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, indent: usize, ending: Ending, @@ -447,7 +457,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( match pred { clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => { print_higher_ranked_params_with_space(bound_params, cx).fmt(f)?; - ty.print(cx).fmt(f)?; + ty.print(ambiguity_table, cx).fmt(f)?; f.write_str(":")?; if !bounds.is_empty() { f.write_str(" ")?; @@ -466,9 +476,14 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( } clean::WherePredicate::EqPredicate { lhs, rhs } => { if f.alternate() { - write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx)) + write!( + f, + "{:#} == {:#}", + lhs.print(ambiguity_table, cx), + rhs.print(cx) + ) } else { - write!(f, "{} == {}", lhs.print(cx), rhs.print(cx)) + write!(f, "{} == {}", lhs.print(ambiguity_table, cx), rhs.print(cx)) } } } @@ -548,10 +563,14 @@ impl clean::Constant { } impl clean::PolyTrait { - fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> { + fn print<'a, 'tcx: 'a>( + &'a self, + ambiguity_table: &AmbiguityTable<'_>, + cx: &'a Context<'tcx>, + ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { print_higher_ranked_params_with_space(&self.generic_params, cx).fmt(f)?; - self.trait_.print(cx).fmt(f) + self.trait_.print(ambiguity_table, cx).fmt(f) }) } } @@ -578,7 +597,11 @@ impl clean::GenericBound { } impl clean::GenericArgs { - fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> { + fn print<'a, 'tcx: 'a>( + &'a self, + ambiguity_table: &AmbiguityTable<'_>, + cx: &'a Context<'tcx>, + ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { match self { clean::GenericArgs::AngleBracketed { args, bindings } => { @@ -606,9 +629,9 @@ impl clean::GenericArgs { } comma = true; if f.alternate() { - write!(f, "{:#}", binding.print(cx))?; + write!(f, "{:#}", binding.print(ambiguity_table, cx))?; } else { - write!(f, "{}", binding.print(cx))?; + write!(f, "{}", binding.print(ambiguity_table, cx))?; } } if f.alternate() { @@ -626,14 +649,14 @@ impl clean::GenericArgs { f.write_str(", ")?; } comma = true; - ty.print(cx).fmt(f)?; + ty.print(ambiguity_table, cx).fmt(f)?; } f.write_str(")")?; if let Some(ref ty) = *output { if f.alternate() { - write!(f, " -> {:#}", ty.print(cx))?; + write!(f, " -> {:#}", ty.print(ambiguity_table, cx))?; } else { - write!(f, " -> {}", ty.print(cx))?; + write!(f, " -> {}", ty.print(ambiguity_table, cx))?; } } } @@ -987,6 +1010,7 @@ fn resolved_path<'cx>( path: &clean::Path, print_all: bool, use_absolute: bool, + ambiguity_table: &AmbiguityTable<'_>, cx: &'cx Context<'_>, ) -> fmt::Result { let last = path.segments.last().unwrap(); @@ -1010,9 +1034,19 @@ fn resolved_path<'cx>( last.name.to_string() } } else { - anchor(did, last.name, cx).to_string() + match ambiguity_table.inner.get(&did) { + Some(path_view) => { + let mut iter = path_view.iter_from_end(); + let end = iter.next().unwrap(); + for seg in iter.rev() { + write!(w, "{}::", seg)?; + } + anchor(did, *end, cx).to_string() + } + None => anchor(did, last.name, cx).to_string(), + } }; - write!(w, "{path}{args}", args = last.args.print(cx))?; + write!(w, "{path}{args}", args = last.args.print(ambiguity_table, cx))?; } Ok(()) } @@ -1404,18 +1438,22 @@ fn fmt_type<'cx>( impl clean::Type { pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>( &'a self, + ambiguity_table: &'b AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'b + Captures<'tcx> { - display_fn(move |f| fmt_type(self, f, false, cx)) + display_fn(move |f| fmt_type(self, f, false, ambiguity_table, cx)) } } impl clean::Path { pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>( &'a self, + ambiguity_table: &'b AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'b + Captures<'tcx> { - display_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx)) + display_fn(move |f| { + resolved_path(f, self.def_id(), self, false, false, ambiguity_table, cx) + }) } } @@ -1423,6 +1461,7 @@ impl clean::Impl { pub(crate) fn print<'a, 'tcx: 'a>( &'a self, use_absolute: bool, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { @@ -1435,7 +1474,7 @@ impl clean::Impl { ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => {} ty::ImplPolarity::Negative => write!(f, "!")?, } - ty.print(cx).fmt(f)?; + ty.print(ambiguity_table, cx).fmt(f)?; write!(f, " for ")?; } @@ -1474,12 +1513,12 @@ impl clean::Impl { // Write output. if !bare_fn.decl.output.is_unit() { write!(f, " -> ")?; - fmt_type(&bare_fn.decl.output, f, use_absolute, cx)?; + fmt_type(&bare_fn.decl.output, f, use_absolute, ambiguity_table, cx)?; } } else if let Some(ty) = self.kind.as_blanket_ty() { - fmt_type(ty, f, use_absolute, cx)?; + fmt_type(ty, f, use_absolute, ambiguity_table, cx)?; } else { - fmt_type(&self.for_, f, use_absolute, cx)?; + fmt_type(&self.for_, f, use_absolute, ambiguity_table, cx)?; } print_where_clause(&self.generics, cx, 0, Ending::Newline).fmt(f) @@ -1919,11 +1958,12 @@ impl clean::ImportSource { impl clean::TypeBinding { pub(crate) fn print<'a, 'tcx: 'a>( &'a self, + ambiguity_table: &AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { f.write_str(self.assoc.name.as_str())?; - self.assoc.args.print(cx).fmt(f)?; + self.assoc.args.print(ambiguity_table, cx).fmt(f)?; match self.kind { clean::TypeBindingKind::Equality { ref term } => { f.write_str(" = ")?; @@ -1932,7 +1972,7 @@ impl clean::TypeBinding { clean::TypeBindingKind::Constraint { ref bounds } => { if !bounds.is_empty() { f.write_str(": ")?; - print_generic_bounds(bounds, cx).fmt(f)?; + print_generic_bounds(bounds, ambiguity_table, cx).fmt(f)?; } } } From 4aaaeab58e176e5d6826e149391ca0f165dcc3fa Mon Sep 17 00:00:00 2001 From: Arthur Carcano Date: Wed, 27 Mar 2024 18:20:14 +0100 Subject: [PATCH 4/6] wip --- src/librustdoc/html/format.rs | 129 ++++++++++++++++++---------------- 1 file changed, 68 insertions(+), 61 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 267e2bb021168..28686601f8825 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -167,6 +167,7 @@ pub(crate) fn comma_sep( pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>( bounds: &'a [clean::GenericBound], + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { @@ -176,7 +177,7 @@ pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>( if i > 0 { f.write_str(" + ")?; } - bound.print(cx).fmt(f)?; + bound.print(ambiguity_table, cx).fmt(f)?; } Ok(()) }) @@ -225,6 +226,11 @@ struct AmbiguityTable<'a> { } impl<'a> AmbiguityTable<'a> { + fn empty() -> Self { + Self { + inner: FxHashMap::default() + } + } fn build() -> AmbiguityTableBuilder<'a> { AmbiguityTableBuilder { inner: FxHashMap::default() } } @@ -368,7 +374,7 @@ impl clean::GenericParamDef { if !bounds.is_empty() { f.write_str(": ")?; - print_generic_bounds(bounds, cx).fmt(f)?; + print_generic_bounds(bounds, ambiguity_table, cx).fmt(f)?; } if let Some(ref ty) = default { @@ -456,12 +462,12 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( match pred { clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => { - print_higher_ranked_params_with_space(bound_params, cx).fmt(f)?; + print_higher_ranked_params_with_space(bound_params, ambiguity_table, cx).fmt(f)?; ty.print(ambiguity_table, cx).fmt(f)?; f.write_str(":")?; if !bounds.is_empty() { f.write_str(" ")?; - print_generic_bounds(bounds, cx).fmt(f)?; + print_generic_bounds(bounds, ambiguity_table,cx).fmt(f)?; } Ok(()) } @@ -470,7 +476,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( // the lifetime nor the bounds contain any characters which need escaping. write!(f, "{}:", lifetime.print())?; if !bounds.is_empty() { - write!(f, " {}", print_generic_bounds(bounds, cx))?; + write!(f, " {}", print_generic_bounds(bounds, ambiguity_table,cx))?; } Ok(()) } @@ -480,10 +486,10 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( f, "{:#} == {:#}", lhs.print(ambiguity_table, cx), - rhs.print(cx) + rhs.print(ambiguity_table, cx) ) } else { - write!(f, "{} == {}", lhs.print(ambiguity_table, cx), rhs.print(cx)) + write!(f, "{} == {}", lhs.print(ambiguity_table, cx), rhs.print(ambiguity_table, cx)) } } } @@ -565,11 +571,11 @@ impl clean::Constant { impl clean::PolyTrait { fn print<'a, 'tcx: 'a>( &'a self, - ambiguity_table: &AmbiguityTable<'_>, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { - print_higher_ranked_params_with_space(&self.generic_params, cx).fmt(f)?; + print_higher_ranked_params_with_space(&self.generic_params, ambiguity_table, cx).fmt(f)?; self.trait_.print(ambiguity_table, cx).fmt(f) }) } @@ -578,6 +584,7 @@ impl clean::PolyTrait { impl clean::GenericBound { pub(crate) fn print<'a, 'tcx: 'a>( &'a self, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self { @@ -590,7 +597,7 @@ impl clean::GenericBound { // `const` and `~const` trait bounds are experimental; don't render them. hir::TraitBoundModifier::Const | hir::TraitBoundModifier::MaybeConst => "", })?; - ty.print(cx).fmt(f) + ty.print(ambiguity_table, cx).fmt(f) } }) } @@ -599,7 +606,7 @@ impl clean::GenericBound { impl clean::GenericArgs { fn print<'a, 'tcx: 'a>( &'a self, - ambiguity_table: &AmbiguityTable<'_>, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { @@ -618,9 +625,9 @@ impl clean::GenericArgs { } comma = true; if f.alternate() { - write!(f, "{:#}", arg.print(cx))?; + write!(f, "{:#}", arg.print(ambiguity_table, cx))?; } else { - write!(f, "{}", arg.print(cx))?; + write!(f, "{}", arg.print(ambiguity_table, cx))?; } } for binding in bindings.iter() { @@ -1021,7 +1028,7 @@ fn resolved_path<'cx>( } } if w.alternate() { - write!(w, "{}{:#}", &last.name, last.args.print(cx))?; + write!(w, "{}{:#}", &last.name, last.args.print(ambiguity_table, cx))?; } else { let path = if use_absolute { if let Ok((_, _, fqp)) = href(did, cx) { @@ -1129,6 +1136,7 @@ fn primitive_link_fragment( fn tybounds<'a, 'tcx: 'a>( bounds: &'a [clean::PolyTrait], lt: &'a Option, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { @@ -1136,7 +1144,7 @@ fn tybounds<'a, 'tcx: 'a>( if i > 0 { write!(f, " + ")?; } - bound.print(cx).fmt(f)?; + bound.print(ambiguity_table, cx).fmt(f)?; } if let Some(lt) = lt { // We don't need to check `alternate` since we can be certain that @@ -1149,12 +1157,13 @@ fn tybounds<'a, 'tcx: 'a>( fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>( params: &'a [clean::GenericParamDef], + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { if !params.is_empty() { f.write_str(if f.alternate() { "for<" } else { "for<" })?; - comma_sep(params.iter().map(|lt| lt.print(cx)), true).fmt(f)?; + comma_sep(params.iter().map(|lt| lt.print(ambiguity_table, cx)), true).fmt(f)?; f.write_str(if f.alternate() { "> " } else { "> " })?; } Ok(()) @@ -1208,7 +1217,7 @@ fn fmt_type<'cx>( primitive_link(f, prim, format_args!("{}", prim.as_sym().as_str()), cx) } clean::BareFunction(ref decl) => { - print_higher_ranked_params_with_space(&decl.generic_params, cx).fmt(f)?; + print_higher_ranked_params_with_space(&decl.generic_params, ambiguity_table, cx).fmt(f)?; decl.unsafety.print_with_space().fmt(f)?; print_abi_with_space(decl.abi).fmt(f)?; if f.alternate() { @@ -1251,7 +1260,7 @@ fn fmt_type<'cx>( if i != 0 { write!(f, ", ")?; } - item.print(cx).fmt(f)?; + item.print(ambiguity_table, cx).fmt(f)?; } write!(f, ")") } @@ -1263,7 +1272,7 @@ fn fmt_type<'cx>( } _ => { write!(f, "[")?; - t.print(cx).fmt(f)?; + t.print(ambiguity_table, cx).fmt(f)?; write!(f, "]") } }, @@ -1276,7 +1285,7 @@ fn fmt_type<'cx>( ), _ => { write!(f, "[")?; - t.print(cx).fmt(f)?; + t.print(ambiguity_table, cx).fmt(f)?; if f.alternate() { write!(f, "; {n}")?; } else { @@ -1298,7 +1307,7 @@ fn fmt_type<'cx>( }; if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() { - let ty = t.print(cx); + let ty = t.print(ambiguity_table, cx); if f.alternate() { primitive_link( f, @@ -1316,7 +1325,7 @@ fn fmt_type<'cx>( } } else { primitive_link(f, clean::PrimitiveType::RawPointer, format_args!("*{m} "), cx)?; - t.print(cx).fmt(f) + t.print(ambiguity_table, cx).fmt(f) } } clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => { @@ -1350,7 +1359,7 @@ fn fmt_type<'cx>( if needs_parens { f.write_str("(")?; } - fmt_type(ty, f, use_absolute, cx)?; + fmt_type(ty, f, use_absolute, ambiguity_table, cx)?; if needs_parens { f.write_str(")")?; } @@ -1358,7 +1367,7 @@ fn fmt_type<'cx>( } clean::ImplTrait(ref bounds) => { f.write_str("impl ")?; - print_generic_bounds(bounds, cx).fmt(f) + print_generic_bounds(bounds, ambiguity_table,cx).fmt(f) } clean::QPath(box clean::QPathData { ref assoc, @@ -1373,17 +1382,17 @@ fn fmt_type<'cx>( if let Some(trait_) = trait_ && should_show_cast { - write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))? + write!(f, "<{:#} as {:#}>::", self_type.print(ambiguity_table, cx), trait_.print(ambiguity_table, cx))? } else { - write!(f, "{:#}::", self_type.print(cx))? + write!(f, "{:#}::", self_type.print(ambiguity_table, cx))? } } else { if let Some(trait_) = trait_ && should_show_cast { - write!(f, "<{} as {}>::", self_type.print(cx), trait_.print(cx))? + write!(f, "<{} as {}>::", self_type.print(ambiguity_table, cx), trait_.print(ambiguity_table, cx))? } else { - write!(f, "{}::", self_type.print(cx))? + write!(f, "{}::", self_type.print(ambiguity_table, cx))? } }; // It's pretty unsightly to look at `::C` in output, and @@ -1430,7 +1439,7 @@ fn fmt_type<'cx>( write!(f, "{}", assoc.name) }?; - assoc.args.print(cx).fmt(f) + assoc.args.print(ambiguity_table, cx).fmt(f) } } } @@ -1466,7 +1475,7 @@ impl clean::Impl { ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { f.write_str("impl")?; - self.generics.print(cx).fmt(f)?; + self.generics.print(ambiguity_table, cx).fmt(f)?; f.write_str(" ")?; if let Some(ref ty) = self.trait_ { @@ -1499,7 +1508,7 @@ impl clean::Impl { // Hardcoded anchor library/core/src/primitive_docs.rs // Link should match `# Trait implementations` - print_higher_ranked_params_with_space(&bare_fn.generic_params, cx).fmt(f)?; + print_higher_ranked_params_with_space(&bare_fn.generic_params, ambiguity_table, cx).fmt(f)?; bare_fn.unsafety.print_with_space().fmt(f)?; print_abi_with_space(bare_fn.abi).fmt(f)?; let ellipsis = if bare_fn.decl.c_variadic { ", ..." } else { "" }; @@ -1521,7 +1530,7 @@ impl clean::Impl { fmt_type(&self.for_, f, use_absolute, ambiguity_table, cx)?; } - print_where_clause(&self.generics, cx, 0, Ending::Newline).fmt(f) + print_where_clause(&self.generics, ambiguity_table, cx, 0, Ending::Newline).fmt(f) }) } } @@ -1529,12 +1538,13 @@ impl clean::Impl { impl clean::Arguments { pub(crate) fn print<'a, 'tcx: 'a>( &'a self, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { for (i, input) in self.values.iter().enumerate() { write!(f, "{}: ", input.name)?; - input.type_.print(cx).fmt(f)?; + input.type_.print(ambiguity_table, cx).fmt(f)?; if i + 1 < self.values.len() { write!(f, ", ")?; } @@ -1569,6 +1579,7 @@ impl Display for Indent { impl clean::FnDecl { pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>( &'a self, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'b + Captures<'tcx> { display_fn(move |f| { @@ -1577,17 +1588,17 @@ impl clean::FnDecl { write!( f, "({args:#}{ellipsis}){arrow:#}", - args = self.inputs.print(cx), + args = self.inputs.print(ambiguity_table, cx), ellipsis = ellipsis, - arrow = self.print_output(cx) + arrow = self.print_output(ambiguity_table, cx) ) } else { write!( f, "({args}{ellipsis}){arrow}", - args = self.inputs.print(cx), + args = self.inputs.print(ambiguity_table, cx), ellipsis = ellipsis, - arrow = self.print_output(cx) + arrow = self.print_output(ambiguity_table, cx) ) } }) @@ -1603,6 +1614,7 @@ impl clean::FnDecl { &'a self, header_len: usize, indent: usize, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { @@ -1672,6 +1684,7 @@ impl clean::FnDecl { // the declaration will be line-wrapped, with an indent of n spaces. line_wrapping_indent: Option, f: &mut fmt::Formatter<'_>, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &Context<'_>, ) -> fmt::Result { let amp = if f.alternate() { "&" } else { "&" }; @@ -1682,11 +1695,6 @@ impl clean::FnDecl { { write!(f, "\n{}", Indent(n + 4))?; } - let mut ambiguity_table_builder = AmbiguityTable::build(); - for inpt in &self.inputs.values { - ambiguity_table_builder.add_type(&inpt.type_) - } - let ambiguity_table = ambiguity_table_builder.finnish(); for (i, input) in self.inputs.values.iter().enumerate() { if i > 0 { match line_wrapping_indent { @@ -1716,7 +1724,7 @@ impl clean::FnDecl { } clean::SelfExplicit(ref typ) => { write!(f, "self: ")?; - typ.print(cx).fmt(f)?; + typ.print(&ambiguity_table, cx).fmt(f)?; } } } else { @@ -1725,13 +1733,7 @@ impl clean::FnDecl { } write!(f, "{}: ", input.name)?; - let use_absolute = input - .type_ - .def_id(cx.cache()) - .and_then(|did| ambiguities.get(&did)) - .map(|rcb| rcb.get()) - .unwrap_or(false); - fmt_type(&input.type_, f, use_absolute, cx)?; + fmt_type(&input.type_, f, false, &ambiguity_table, cx)?; } } @@ -1747,19 +1749,20 @@ impl clean::FnDecl { Some(n) => write!(f, "\n{})", Indent(n))?, }; - self.print_output(cx).fmt(f) + self.print_output(&ambiguity_table, cx).fmt(f) } fn print_output<'a, 'tcx: 'a>( &'a self, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match &self.output { clean::Tuple(tys) if tys.is_empty() => Ok(()), ty if f.alternate() => { - write!(f, " -> {:#}", ty.print(cx)) + write!(f, " -> {:#}", ty.print(ambiguity_table, cx)) } - ty => write!(f, " -> {}", ty.print(cx)), + ty => write!(f, " -> {}", ty.print(ambiguity_table, cx)), }) } } @@ -1906,21 +1909,22 @@ pub(crate) fn print_constness_with_space( impl clean::Import { pub(crate) fn print<'a, 'tcx: 'a>( &'a self, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self.kind { clean::ImportKind::Simple(name) => { if name == self.source.path.last() { - write!(f, "use {};", self.source.print(cx)) + write!(f, "use {};", self.source.print(ambiguity_table, cx)) } else { - write!(f, "use {source} as {name};", source = self.source.print(cx)) + write!(f, "use {source} as {name};", source = self.source.print(ambiguity_table, cx)) } } clean::ImportKind::Glob => { if self.source.path.segments.is_empty() { write!(f, "use *;") } else { - write!(f, "use {}::*;", self.source.print(cx)) + write!(f, "use {}::*;", self.source.print(ambiguity_table, cx)) } } }) @@ -1930,10 +1934,11 @@ impl clean::Import { impl clean::ImportSource { pub(crate) fn print<'a, 'tcx: 'a>( &'a self, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self.did { - Some(did) => resolved_path(f, did, &self.path, true, false, cx), + Some(did) => resolved_path(f, did, &self.path, true, false, ambiguity_table, cx), _ => { for seg in &self.path.segments[..self.path.segments.len() - 1] { write!(f, "{}::", seg.name)?; @@ -1958,7 +1963,7 @@ impl clean::ImportSource { impl clean::TypeBinding { pub(crate) fn print<'a, 'tcx: 'a>( &'a self, - ambiguity_table: &AmbiguityTable<'_>, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { @@ -1967,7 +1972,7 @@ impl clean::TypeBinding { match self.kind { clean::TypeBindingKind::Equality { ref term } => { f.write_str(" = ")?; - term.print(cx).fmt(f)?; + term.print(ambiguity_table, cx).fmt(f)?; } clean::TypeBindingKind::Constraint { ref bounds } => { if !bounds.is_empty() { @@ -1998,11 +2003,12 @@ pub(crate) fn print_default_space<'a>(v: bool) -> &'a str { impl clean::GenericArg { pub(crate) fn print<'a, 'tcx: 'a>( &'a self, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self { clean::GenericArg::Lifetime(lt) => lt.print().fmt(f), - clean::GenericArg::Type(ty) => ty.print(cx).fmt(f), + clean::GenericArg::Type(ty) => ty.print(ambiguity_table, cx).fmt(f), clean::GenericArg::Const(ct) => ct.print(cx.tcx()).fmt(f), clean::GenericArg::Infer => Display::fmt("_", f), }) @@ -2012,10 +2018,11 @@ impl clean::GenericArg { impl clean::Term { pub(crate) fn print<'a, 'tcx: 'a>( &'a self, + ambiguity_table: &'a AmbiguityTable<'_>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self { - clean::Term::Type(ty) => ty.print(cx).fmt(f), + clean::Term::Type(ty) => ty.print(ambiguity_table, cx).fmt(f), clean::Term::Constant(ct) => ct.print(cx.tcx()).fmt(f), }) } From 1395405eacc459b7af007c898b6c44b53d6542b2 Mon Sep 17 00:00:00 2001 From: Arthur Carcano Date: Fri, 29 Mar 2024 12:02:21 +0100 Subject: [PATCH 5/6] wip --- src/librustdoc/html/ambiguity.rs | 190 ++++++++++ src/librustdoc/html/format.rs | 462 +++++++---------------- src/librustdoc/html/mod.rs | 1 + src/librustdoc/html/render/context.rs | 13 +- src/librustdoc/html/render/mod.rs | 6 +- src/librustdoc/html/render/print_item.rs | 24 +- 6 files changed, 343 insertions(+), 353 deletions(-) create mode 100644 src/librustdoc/html/ambiguity.rs diff --git a/src/librustdoc/html/ambiguity.rs b/src/librustdoc/html/ambiguity.rs new file mode 100644 index 0000000000000..cf50497debdac --- /dev/null +++ b/src/librustdoc/html/ambiguity.rs @@ -0,0 +1,190 @@ +#![allow(warnings)] +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def_id::DefId; +use rustc_span::Symbol; + +use crate::clean::{self, FnDecl, Function}; + +#[derive(Debug, Clone)] +pub struct PathLike<'a> { + path: &'a clean::Path, + suffix_len: usize, +} + +impl<'a> PathLike<'a> { + pub fn make_longer(self) -> Self { + let Self { path, suffix_len } = self; + assert!(suffix_len < path.segments.len()); + Self { path, suffix_len: suffix_len + 1 } + } + + pub fn iter_from_end(&self) -> impl DoubleEndedIterator { + self.path.segments.iter().map(|seg| &seg.name).rev().take(self.suffix_len) + } +} + +impl<'a> Eq for PathLike<'a> {} +impl<'a> PartialEq for PathLike<'a> { + fn eq(&self, other: &Self) -> bool { + if self.suffix_len != other.suffix_len { + return false; + } + let self_suffix = self.iter_from_end(); + let other_suffix = self.iter_from_end(); + self_suffix.zip(other_suffix).all(|(s, o)| s.eq(o)) + } +} + +impl<'a> std::hash::Hash for PathLike<'a> { + fn hash(&self, state: &mut H) { + for sym in self.iter_from_end() { + sym.hash(state) + } + } +} + +#[derive(Debug, Clone)] +pub struct AmbiguityTable<'a> { + inner: FxHashMap>, +} + +impl<'a> AmbiguityTable<'a> { + pub fn empty() -> Self { + Self { inner: FxHashMap::default() } + } + + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + pub fn build() -> AmbiguityTableBuilder<'a> { + AmbiguityTableBuilder { inner: FxHashMap::default() } + } + + pub fn get(&self, x: &DefId) -> Option<&PathLike<'a>> { + self.inner.get(x) + } +} + +enum AmbiguityTableBuilderEntry { + MapsToOne(DefId), + IsAmbiguous, +} + +pub struct AmbiguityTableBuilder<'a> { + inner: FxHashMap, AmbiguityTableBuilderEntry>, +} + +impl<'a> AmbiguityTableBuilder<'a> { + // Invariant: must start with length 1 path view + fn add_path_view(&mut self, p: PathLike<'a>, did: DefId) { + use std::collections::hash_map::Entry::*; + // TODO: clone + match self.inner.entry(p.clone()) { + Occupied(entry) => { + let v = + std::mem::replace(entry.into_mut(), AmbiguityTableBuilderEntry::IsAmbiguous); + let p = p.make_longer(); + match v { + AmbiguityTableBuilderEntry::MapsToOne(other_did) => { + self.add_path_view(p.clone(), other_did) + } + AmbiguityTableBuilderEntry::IsAmbiguous => (), + } + self.add_path_view(p.clone(), did) + } + Vacant(entry) => { + entry.insert(AmbiguityTableBuilderEntry::MapsToOne(did)); + } + } + } + + fn add_path(&mut self, path: &'a clean::Path) { + let pv = PathLike { path, suffix_len: 1 }; + self.add_path_view(pv, path.def_id()) + } + + fn add_generic_bound(&mut self, generic_bound: &'a clean::GenericBound) { + match generic_bound { + clean::GenericBound::TraitBound(poly_trait, _) => self.add_poly_trait(poly_trait), + clean::GenericBound::Outlives(_) => (), + } + } + + fn add_poly_trait(&mut self, poly_trait: &'a clean::PolyTrait) { + // TODO: also add potential bounds on trait parameters + self.add_path(&poly_trait.trait_); + for gen_param in &poly_trait.generic_params { + use clean::GenericParamDefKind::*; + match &gen_param.kind { + Type { bounds, .. } => { + for bnd in bounds { + self.add_generic_bound(bnd) + } + } + Lifetime { .. } | Const { .. } => (), + } + } + } + + fn add_type(&mut self, ty: &'a clean::Type) { + match ty { + clean::Type::Path { path } => self.add_path(path), + clean::Type::Tuple(tys) => { + for ty in tys { + self.add_type(ty) + } + } + clean::Type::RawPointer(_, ty) + | clean::Type::Slice(ty) + | clean::Type::BorrowedRef { type_: ty, .. } + | clean::Type::Array(ty, _) => self.add_type(ty), + + clean::Type::DynTrait(poly_trait, _) => { + for trai in poly_trait { + self.add_poly_trait(trai) + } + } + + clean::Type::BareFunction(bare_func_decl) => { + let clean::FnDecl { output, inputs, .. } = &bare_func_decl.decl; + self.add_type(output); + for inpt in &inputs.values { + self.add_type(&inpt.type_) + } + } + clean::Type::ImplTrait(bnds) => { + for bnd in bnds { + self.add_generic_bound(bnd) + } + } + clean::Type::Infer + | clean::Type::QPath(_) + | clean::Type::Primitive(_) + | clean::Type::Generic(_) => (), + } + } + + fn add_fndecl(&mut self, decl: &'a FnDecl) { + for arg in &decl.inputs.values { + self.add_type(&arg.type_); + } + self.add_type(&decl.output); + } + + pub fn add_fn(mut self, f: &'a Function) -> Self{ + self.add_fndecl(&f.decl); + self + } + + pub fn finnish(self) -> AmbiguityTable<'a> { + let mut inner = FxHashMap::default(); + for (path_view, did) in self.inner { + if let AmbiguityTableBuilderEntry::MapsToOne(did) = did { + let hopefully_none = inner.insert(did, path_view); + assert!(hopefully_none.is_none()); + } + } + AmbiguityTable { inner } + } +} diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 28686601f8825..ab1c43f638682 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -15,7 +15,6 @@ use std::iter::{self, once}; use rustc_ast as ast; use rustc_attr::{ConstStability, StabilityLevel}; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -165,10 +164,9 @@ pub(crate) fn comma_sep( }) } -pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>( +pub(crate) fn print_generic_bounds<'a, 'tcx: 'a, 'at: 'a>( bounds: &'a [clean::GenericBound], - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { let mut bounds_dup = FxHashSet::default(); @@ -177,181 +175,16 @@ pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>( if i > 0 { f.write_str(" + ")?; } - bound.print(ambiguity_table, cx).fmt(f)?; + bound.print(cx).fmt(f)?; } Ok(()) }) } -#[derive(Clone)] -struct PathView<'a> { - path: &'a clean::Path, - suffix_len: usize, -} - -impl<'a> PathView<'a> { - fn make_longer(self) -> Self { - let Self { path, suffix_len } = self; - assert!(suffix_len < path.segments.len()); - Self { path, suffix_len: suffix_len + 1 } - } - - fn iter_from_end(&self) -> impl DoubleEndedIterator { - self.path.segments.iter().map(|seg| &seg.name).rev().take(self.suffix_len) - } -} - -impl<'a> Eq for PathView<'a> {} -impl<'a> PartialEq for PathView<'a> { - fn eq(&self, other: &Self) -> bool { - if self.suffix_len != other.suffix_len { - return false; - } - let self_suffix = self.iter_from_end(); - let other_suffix = self.iter_from_end(); - self_suffix.zip(other_suffix).all(|(s, o)| s.eq(o)) - } -} - -impl<'a> std::hash::Hash for PathView<'a> { - fn hash(&self, state: &mut H) { - for sym in self.iter_from_end() { - sym.hash(state) - } - } -} - -struct AmbiguityTable<'a> { - inner: FxHashMap>, -} - -impl<'a> AmbiguityTable<'a> { - fn empty() -> Self { - Self { - inner: FxHashMap::default() - } - } - fn build() -> AmbiguityTableBuilder<'a> { - AmbiguityTableBuilder { inner: FxHashMap::default() } - } -} - -enum AmbiguityTableBuilderEntry { - MapsToOne(DefId), - IsAmbiguous, -} - -struct AmbiguityTableBuilder<'a> { - inner: FxHashMap, AmbiguityTableBuilderEntry>, -} - -impl<'a> AmbiguityTableBuilder<'a> { - // Invariant: must start with length 1 path view - fn add_path_view(&mut self, p: PathView<'a>, did: DefId) { - use std::collections::hash_map::Entry::*; - // TODO: clone - match self.inner.entry(p.clone()) { - Occupied(entry) => { - let v = - std::mem::replace(entry.into_mut(), AmbiguityTableBuilderEntry::IsAmbiguous); - let p = p.make_longer(); - match v { - AmbiguityTableBuilderEntry::MapsToOne(other_did) => { - self.add_path_view(p.clone(), other_did) - } - AmbiguityTableBuilderEntry::IsAmbiguous => (), - } - self.add_path_view(p.clone(), did) - } - Vacant(entry) => { - entry.insert(AmbiguityTableBuilderEntry::MapsToOne(did)); - } - } - } - - fn add_path(&mut self, path: &'a clean::Path) { - let pv = PathView { path, suffix_len: 1 }; - self.add_path_view(pv, path.def_id()) - } - - fn add_generic_bound(&mut self, generic_bound: &'a clean::GenericBound) { - match generic_bound { - clean::GenericBound::TraitBound(poly_trait, _) => self.add_poly_trait(poly_trait), - clean::GenericBound::Outlives(_) => (), - } - } - - fn add_poly_trait(&mut self, poly_trait: &'a clean::PolyTrait) { - // TODO: also add potential bounds on trait parameters - self.add_path(&poly_trait.trait_); - for gen_param in &poly_trait.generic_params { - use clean::GenericParamDefKind::*; - match &gen_param.kind { - Type { bounds, .. } => { - for bnd in bounds { - self.add_generic_bound(bnd) - } - } - Lifetime { .. } | Const { .. } => (), - } - } - } - - fn add_type(&mut self, ty: &'a clean::Type) { - match ty { - clean::Type::Path { path } => self.add_path(path), - clean::Type::Tuple(tys) => { - for ty in tys { - self.add_type(ty) - } - } - clean::Type::RawPointer(_, ty) - | clean::Type::Slice(ty) - | clean::Type::BorrowedRef { type_: ty, .. } - | clean::Type::Array(ty, _) => self.add_type(ty), - - clean::Type::DynTrait(poly_trait, _) => { - for trai in poly_trait { - self.add_poly_trait(trai) - } - } - - clean::Type::BareFunction(bare_func_decl) => { - let clean::FnDecl { output, inputs, .. } = &bare_func_decl.decl; - self.add_type(output); - for inpt in &inputs.values { - self.add_type(&inpt.type_) - } - } - clean::Type::ImplTrait(bnds) => { - for bnd in bnds { - self.add_generic_bound(bnd) - } - } - clean::Type::Infer - | clean::Type::QPath(_) - | clean::Type::Primitive(_) - | clean::Type::Generic(_) => (), - } - } - - fn finnish(self) -> AmbiguityTable<'a> { - let mut inner = FxHashMap::default(); - for (path_view, did) in self.inner { - if let AmbiguityTableBuilderEntry::MapsToOne(did) = did { - let hopefully_none = inner.insert(did, path_view); - assert!(hopefully_none.is_none()); - } - } - AmbiguityTable { inner } - } -} - impl clean::GenericParamDef { - pub(crate) fn print<'a, 'tcx: 'a>( + pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( &'a self, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match &self.kind { clean::GenericParamDefKind::Lifetime { outlives } => { @@ -374,19 +207,19 @@ impl clean::GenericParamDef { if !bounds.is_empty() { f.write_str(": ")?; - print_generic_bounds(bounds, ambiguity_table, cx).fmt(f)?; + print_generic_bounds(bounds, cx).fmt(f)?; } if let Some(ref ty) = default { f.write_str(" = ")?; - ty.print(ambiguity_table, cx).fmt(f)?; + ty.print(cx).fmt(f)?; } Ok(()) } clean::GenericParamDefKind::Const { ty, default, .. } => { write!(f, "const {}: ", self.name)?; - ty.print(ambiguity_table, cx).fmt(f)?; + ty.print(cx).fmt(f)?; if let Some(default) = default { f.write_str(" = ")?; @@ -404,10 +237,9 @@ impl clean::GenericParamDef { } impl clean::Generics { - pub(crate) fn print<'a, 'tcx: 'a>( + pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( &'a self, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable(); @@ -416,17 +248,9 @@ impl clean::Generics { } if f.alternate() { - write!( - f, - "<{:#}>", - comma_sep(real_params.map(|g| g.print(ambiguity_table, cx)), true) - ) + write!(f, "<{:#}>", comma_sep(real_params.map(|g| g.print(cx)), true)) } else { - write!( - f, - "<{}>", - comma_sep(real_params.map(|g| g.print(ambiguity_table, cx)), true) - ) + write!(f, "<{}>", comma_sep(real_params.map(|g| g.print(cx)), true)) } }) } @@ -441,10 +265,9 @@ pub(crate) enum Ending { /// * The Generics from which to emit a where-clause. /// * The number of spaces to indent each line with. /// * Whether the where-clause needs to add a comma and newline after the last bound. -pub(crate) fn print_where_clause<'a, 'tcx: 'a>( +pub(crate) fn print_where_clause<'a, 'tcx: 'a, 'at: 'a>( gens: &'a clean::Generics, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, indent: usize, ending: Ending, ) -> impl Display + 'a + Captures<'tcx> { @@ -462,12 +285,12 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( match pred { clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => { - print_higher_ranked_params_with_space(bound_params, ambiguity_table, cx).fmt(f)?; - ty.print(ambiguity_table, cx).fmt(f)?; + print_higher_ranked_params_with_space(bound_params, cx).fmt(f)?; + ty.print(cx).fmt(f)?; f.write_str(":")?; if !bounds.is_empty() { f.write_str(" ")?; - print_generic_bounds(bounds, ambiguity_table,cx).fmt(f)?; + print_generic_bounds(bounds, cx).fmt(f)?; } Ok(()) } @@ -476,20 +299,15 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( // the lifetime nor the bounds contain any characters which need escaping. write!(f, "{}:", lifetime.print())?; if !bounds.is_empty() { - write!(f, " {}", print_generic_bounds(bounds, ambiguity_table,cx))?; + write!(f, " {}", print_generic_bounds(bounds, cx))?; } Ok(()) } clean::WherePredicate::EqPredicate { lhs, rhs } => { if f.alternate() { - write!( - f, - "{:#} == {:#}", - lhs.print(ambiguity_table, cx), - rhs.print(ambiguity_table, cx) - ) + write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx)) } else { - write!(f, "{} == {}", lhs.print(ambiguity_table, cx), rhs.print(ambiguity_table, cx)) + write!(f, "{} == {}", lhs.print(cx), rhs.print(cx)) } } } @@ -569,23 +387,18 @@ impl clean::Constant { } impl clean::PolyTrait { - fn print<'a, 'tcx: 'a>( - &'a self, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, - ) -> impl Display + 'a + Captures<'tcx> { + fn print<'a, 'tcx: 'a, 'at: 'a>(&'a self, cx: &'a Context<'tcx, 'at>) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { - print_higher_ranked_params_with_space(&self.generic_params, ambiguity_table, cx).fmt(f)?; - self.trait_.print(ambiguity_table, cx).fmt(f) + print_higher_ranked_params_with_space(&self.generic_params, cx).fmt(f)?; + self.trait_.print(cx).fmt(f) }) } } impl clean::GenericBound { - pub(crate) fn print<'a, 'tcx: 'a>( + pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( &'a self, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self { clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()), @@ -597,18 +410,14 @@ impl clean::GenericBound { // `const` and `~const` trait bounds are experimental; don't render them. hir::TraitBoundModifier::Const | hir::TraitBoundModifier::MaybeConst => "", })?; - ty.print(ambiguity_table, cx).fmt(f) + ty.print(cx).fmt(f) } }) } } impl clean::GenericArgs { - fn print<'a, 'tcx: 'a>( - &'a self, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, - ) -> impl Display + 'a + Captures<'tcx> { + fn print<'a, 'tcx: 'a, 'at: 'a>(&'a self, cx: &'a Context<'tcx, 'at>) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { match self { clean::GenericArgs::AngleBracketed { args, bindings } => { @@ -625,9 +434,9 @@ impl clean::GenericArgs { } comma = true; if f.alternate() { - write!(f, "{:#}", arg.print(ambiguity_table, cx))?; + write!(f, "{:#}", arg.print(cx))?; } else { - write!(f, "{}", arg.print(ambiguity_table, cx))?; + write!(f, "{}", arg.print(cx))?; } } for binding in bindings.iter() { @@ -636,9 +445,9 @@ impl clean::GenericArgs { } comma = true; if f.alternate() { - write!(f, "{:#}", binding.print(ambiguity_table, cx))?; + write!(f, "{:#}", binding.print(cx))?; } else { - write!(f, "{}", binding.print(ambiguity_table, cx))?; + write!(f, "{}", binding.print(cx))?; } } if f.alternate() { @@ -656,14 +465,14 @@ impl clean::GenericArgs { f.write_str(", ")?; } comma = true; - ty.print(ambiguity_table, cx).fmt(f)?; + ty.print(cx).fmt(f)?; } f.write_str(")")?; if let Some(ref ty) = *output { if f.alternate() { - write!(f, " -> {:#}", ty.print(ambiguity_table, cx))?; + write!(f, " -> {:#}", ty.print(cx))?; } else { - write!(f, " -> {}", ty.print(ambiguity_table, cx))?; + write!(f, " -> {}", ty.print(cx))?; } } } @@ -716,7 +525,7 @@ pub(crate) fn join_with_double_colon(syms: &[Symbol]) -> String { /// `href_with_root_path`. fn generate_macro_def_id_path( def_id: DefId, - cx: &Context<'_>, + cx: &Context<'_, '_>, root_path: Option<&str>, ) -> Result<(String, ItemType, Vec), HrefError> { let tcx = cx.tcx(); @@ -781,7 +590,7 @@ fn generate_macro_def_id_path( fn generate_item_def_id_path( mut def_id: DefId, original_def_id: DefId, - cx: &Context<'_>, + cx: &Context<'_, '_>, root_path: Option<&str>, original_def_kind: DefKind, ) -> Result<(String, ItemType, Vec), HrefError> { @@ -874,7 +683,7 @@ fn make_href( pub(crate) fn href_with_root_path( original_did: DefId, - cx: &Context<'_>, + cx: &Context<'_, '_>, root_path: Option<&str>, ) -> Result<(String, ItemType, Vec), HrefError> { let tcx = cx.tcx(); @@ -944,7 +753,7 @@ pub(crate) fn href_with_root_path( pub(crate) fn href( did: DefId, - cx: &Context<'_>, + cx: &Context<'_, '_>, ) -> Result<(String, ItemType, Vec), HrefError> { href_with_root_path(did, cx, None) } @@ -981,7 +790,7 @@ pub(crate) fn href_relative_parts<'fqp>( } } -pub(crate) fn link_tooltip(did: DefId, fragment: &Option, cx: &Context<'_>) -> String { +pub(crate) fn link_tooltip(did: DefId, fragment: &Option, cx: &Context<'_, '_>,) -> String { let cache = cx.cache(); let Some((fqp, shortty)) = cache.paths.get(&did).or_else(|| cache.external_paths.get(&did)) else { @@ -1017,8 +826,7 @@ fn resolved_path<'cx>( path: &clean::Path, print_all: bool, use_absolute: bool, - ambiguity_table: &AmbiguityTable<'_>, - cx: &'cx Context<'_>, + cx: &'cx Context<'_, '_>, ) -> fmt::Result { let last = path.segments.last().unwrap(); @@ -1028,7 +836,7 @@ fn resolved_path<'cx>( } } if w.alternate() { - write!(w, "{}{:#}", &last.name, last.args.print(ambiguity_table, cx))?; + write!(w, "{}{:#}", &last.name, last.args.print(cx))?; } else { let path = if use_absolute { if let Ok((_, _, fqp)) = href(did, cx) { @@ -1041,7 +849,7 @@ fn resolved_path<'cx>( last.name.to_string() } } else { - match ambiguity_table.inner.get(&did) { + match cx.ambiguity_table.get(&did) { Some(path_view) => { let mut iter = path_view.iter_from_end(); let end = iter.next().unwrap(); @@ -1053,7 +861,7 @@ fn resolved_path<'cx>( None => anchor(did, last.name, cx).to_string(), } }; - write!(w, "{path}{args}", args = last.args.print(ambiguity_table, cx))?; + write!(w, "{path}{args}", args = last.args.print(cx))?; } Ok(()) } @@ -1062,7 +870,7 @@ fn primitive_link( f: &mut fmt::Formatter<'_>, prim: clean::PrimitiveType, name: fmt::Arguments<'_>, - cx: &Context<'_>, + cx: &Context<'_, '_>, ) -> fmt::Result { primitive_link_fragment(f, prim, name, "", cx) } @@ -1072,7 +880,7 @@ fn primitive_link_fragment( prim: clean::PrimitiveType, name: fmt::Arguments<'_>, fragment: &str, - cx: &Context<'_>, + cx: &Context<'_, '_>, ) -> fmt::Result { let m = &cx.cache(); let mut needs_termination = false; @@ -1133,18 +941,17 @@ fn primitive_link_fragment( Ok(()) } -fn tybounds<'a, 'tcx: 'a>( +fn tybounds<'a, 'tcx: 'a, 'at: 'a>( bounds: &'a [clean::PolyTrait], lt: &'a Option, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { for (i, bound) in bounds.iter().enumerate() { if i > 0 { write!(f, " + ")?; } - bound.print(ambiguity_table, cx).fmt(f)?; + bound.print(cx).fmt(f)?; } if let Some(lt) = lt { // We don't need to check `alternate` since we can be certain that @@ -1155,15 +962,14 @@ fn tybounds<'a, 'tcx: 'a>( }) } -fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>( +fn print_higher_ranked_params_with_space<'a, 'tcx: 'a, 'at: 'a>( params: &'a [clean::GenericParamDef], - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { if !params.is_empty() { f.write_str(if f.alternate() { "for<" } else { "for<" })?; - comma_sep(params.iter().map(|lt| lt.print(ambiguity_table, cx)), true).fmt(f)?; + comma_sep(params.iter().map(|lt| lt.print(cx)), true).fmt(f)?; f.write_str(if f.alternate() { "> " } else { "> " })?; } Ok(()) @@ -1173,7 +979,7 @@ fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>( pub(crate) fn anchor<'a, 'cx: 'a>( did: DefId, text: Symbol, - cx: &'cx Context<'_>, + cx: &'cx Context<'_, '_>, ) -> impl Display + 'a { let parts = href(did, cx); display_fn(move |f| { @@ -1193,8 +999,7 @@ fn fmt_type<'cx>( t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool, - ambiguity_table: &AmbiguityTable<'_>, - cx: &'cx Context<'_>, + cx: &'cx Context<'_, '_>, ) -> fmt::Result { trace!("fmt_type(t = {t:?})"); @@ -1203,11 +1008,11 @@ fn fmt_type<'cx>( clean::Type::Path { ref path } => { // Paths like `T::Output` and `Self::Output` should be rendered with all segments. let did = path.def_id(); - resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, ambiguity_table, cx) + resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, cx) } clean::DynTrait(ref bounds, ref lt) => { f.write_str("dyn ")?; - tybounds(bounds, lt, ambiguity_table, cx).fmt(f) + tybounds(bounds, lt, cx).fmt(f) } clean::Infer => write!(f, "_"), clean::Primitive(clean::PrimitiveType::Never) => { @@ -1217,7 +1022,7 @@ fn fmt_type<'cx>( primitive_link(f, prim, format_args!("{}", prim.as_sym().as_str()), cx) } clean::BareFunction(ref decl) => { - print_higher_ranked_params_with_space(&decl.generic_params, ambiguity_table, cx).fmt(f)?; + print_higher_ranked_params_with_space(&decl.generic_params, cx).fmt(f)?; decl.unsafety.print_with_space().fmt(f)?; print_abi_with_space(decl.abi).fmt(f)?; if f.alternate() { @@ -1225,7 +1030,7 @@ fn fmt_type<'cx>( } else { primitive_link(f, PrimitiveType::Fn, format_args!("fn"), cx)?; } - decl.decl.print(ambiguity_table, cx).fmt(f) + decl.decl.print(cx).fmt(f) } clean::Tuple(ref typs) => match &typs[..] { &[] => primitive_link(f, PrimitiveType::Unit, format_args!("()"), cx), @@ -1234,7 +1039,7 @@ fn fmt_type<'cx>( primitive_link(f, PrimitiveType::Tuple, format_args!("({name},)"), cx) } else { write!(f, "(")?; - one.print(ambiguity_table, cx).fmt(f)?; + one.print(cx).fmt(f)?; write!(f, ",)") } } @@ -1260,7 +1065,7 @@ fn fmt_type<'cx>( if i != 0 { write!(f, ", ")?; } - item.print(ambiguity_table, cx).fmt(f)?; + item.print(cx).fmt(f)?; } write!(f, ")") } @@ -1272,7 +1077,7 @@ fn fmt_type<'cx>( } _ => { write!(f, "[")?; - t.print(ambiguity_table, cx).fmt(f)?; + t.print(cx).fmt(f)?; write!(f, "]") } }, @@ -1285,7 +1090,7 @@ fn fmt_type<'cx>( ), _ => { write!(f, "[")?; - t.print(ambiguity_table, cx).fmt(f)?; + t.print(cx).fmt(f)?; if f.alternate() { write!(f, "; {n}")?; } else { @@ -1307,7 +1112,7 @@ fn fmt_type<'cx>( }; if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() { - let ty = t.print(ambiguity_table, cx); + let ty = t.print(cx); if f.alternate() { primitive_link( f, @@ -1325,7 +1130,7 @@ fn fmt_type<'cx>( } } else { primitive_link(f, clean::PrimitiveType::RawPointer, format_args!("*{m} "), cx)?; - t.print(ambiguity_table, cx).fmt(f) + t.print(cx).fmt(f) } } clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => { @@ -1359,7 +1164,7 @@ fn fmt_type<'cx>( if needs_parens { f.write_str("(")?; } - fmt_type(ty, f, use_absolute, ambiguity_table, cx)?; + fmt_type(ty, f, use_absolute, cx)?; if needs_parens { f.write_str(")")?; } @@ -1367,7 +1172,7 @@ fn fmt_type<'cx>( } clean::ImplTrait(ref bounds) => { f.write_str("impl ")?; - print_generic_bounds(bounds, ambiguity_table,cx).fmt(f) + print_generic_bounds(bounds, cx).fmt(f) } clean::QPath(box clean::QPathData { ref assoc, @@ -1382,17 +1187,17 @@ fn fmt_type<'cx>( if let Some(trait_) = trait_ && should_show_cast { - write!(f, "<{:#} as {:#}>::", self_type.print(ambiguity_table, cx), trait_.print(ambiguity_table, cx))? + write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))? } else { - write!(f, "{:#}::", self_type.print(ambiguity_table, cx))? + write!(f, "{:#}::", self_type.print(cx))? } } else { if let Some(trait_) = trait_ && should_show_cast { - write!(f, "<{} as {}>::", self_type.print(ambiguity_table, cx), trait_.print(ambiguity_table, cx))? + write!(f, "<{} as {}>::", self_type.print(cx), trait_.print(cx))? } else { - write!(f, "{}::", self_type.print(ambiguity_table, cx))? + write!(f, "{}::", self_type.print(cx))? } }; // It's pretty unsightly to look at `::C` in output, and @@ -1439,43 +1244,38 @@ fn fmt_type<'cx>( write!(f, "{}", assoc.name) }?; - assoc.args.print(ambiguity_table, cx).fmt(f) + assoc.args.print(cx).fmt(f) } } } impl clean::Type { - pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>( + pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a, 'at: 'a>( &'a self, - ambiguity_table: &'b AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'b + Captures<'tcx> { - display_fn(move |f| fmt_type(self, f, false, ambiguity_table, cx)) + display_fn(move |f| fmt_type(self, f, false, cx)) } } impl clean::Path { - pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>( + pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a, 'at: 'a>( &'a self, - ambiguity_table: &'b AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'b + Captures<'tcx> { - display_fn(move |f| { - resolved_path(f, self.def_id(), self, false, false, ambiguity_table, cx) - }) + display_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx)) } } impl clean::Impl { - pub(crate) fn print<'a, 'tcx: 'a>( + pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( &'a self, use_absolute: bool, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { f.write_str("impl")?; - self.generics.print(ambiguity_table, cx).fmt(f)?; + self.generics.print(cx).fmt(f)?; f.write_str(" ")?; if let Some(ref ty) = self.trait_ { @@ -1483,7 +1283,7 @@ impl clean::Impl { ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => {} ty::ImplPolarity::Negative => write!(f, "!")?, } - ty.print(ambiguity_table, cx).fmt(f)?; + ty.print(cx).fmt(f)?; write!(f, " for ")?; } @@ -1508,7 +1308,7 @@ impl clean::Impl { // Hardcoded anchor library/core/src/primitive_docs.rs // Link should match `# Trait implementations` - print_higher_ranked_params_with_space(&bare_fn.generic_params, ambiguity_table, cx).fmt(f)?; + print_higher_ranked_params_with_space(&bare_fn.generic_params, cx).fmt(f)?; bare_fn.unsafety.print_with_space().fmt(f)?; print_abi_with_space(bare_fn.abi).fmt(f)?; let ellipsis = if bare_fn.decl.c_variadic { ", ..." } else { "" }; @@ -1522,29 +1322,28 @@ impl clean::Impl { // Write output. if !bare_fn.decl.output.is_unit() { write!(f, " -> ")?; - fmt_type(&bare_fn.decl.output, f, use_absolute, ambiguity_table, cx)?; + fmt_type(&bare_fn.decl.output, f, use_absolute, cx)?; } } else if let Some(ty) = self.kind.as_blanket_ty() { - fmt_type(ty, f, use_absolute, ambiguity_table, cx)?; + fmt_type(ty, f, use_absolute, cx)?; } else { - fmt_type(&self.for_, f, use_absolute, ambiguity_table, cx)?; + fmt_type(&self.for_, f, use_absolute, cx)?; } - print_where_clause(&self.generics, ambiguity_table, cx, 0, Ending::Newline).fmt(f) + print_where_clause(&self.generics, cx, 0, Ending::Newline).fmt(f) }) } } impl clean::Arguments { - pub(crate) fn print<'a, 'tcx: 'a>( + pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( &'a self, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { for (i, input) in self.values.iter().enumerate() { write!(f, "{}: ", input.name)?; - input.type_.print(ambiguity_table, cx).fmt(f)?; + input.type_.print(cx).fmt(f)?; if i + 1 < self.values.len() { write!(f, ", ")?; } @@ -1577,10 +1376,9 @@ impl Display for Indent { } impl clean::FnDecl { - pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>( + pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a, 'at: 'a>( &'a self, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'b + Captures<'tcx> { display_fn(move |f| { let ellipsis = if self.c_variadic { ", ..." } else { "" }; @@ -1588,17 +1386,17 @@ impl clean::FnDecl { write!( f, "({args:#}{ellipsis}){arrow:#}", - args = self.inputs.print(ambiguity_table, cx), + args = self.inputs.print(cx), ellipsis = ellipsis, - arrow = self.print_output(ambiguity_table, cx) + arrow = self.print_output(cx) ) } else { write!( f, "({args}{ellipsis}){arrow}", - args = self.inputs.print(ambiguity_table, cx), + args = self.inputs.print(cx), ellipsis = ellipsis, - arrow = self.print_output(ambiguity_table, cx) + arrow = self.print_output(cx) ) } }) @@ -1610,12 +1408,11 @@ impl clean::FnDecl { /// are preserved. /// * `indent`: The number of spaces to indent each successive line with, if line-wrapping is /// necessary. - pub(crate) fn full_print<'a, 'tcx: 'a>( + pub(crate) fn full_print<'a, 'tcx: 'a, 'at: 'a>( &'a self, header_len: usize, indent: usize, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { // First, generate the text form of the declaration, with no line wrapping, and count the bytes. @@ -1684,8 +1481,7 @@ impl clean::FnDecl { // the declaration will be line-wrapped, with an indent of n spaces. line_wrapping_indent: Option, f: &mut fmt::Formatter<'_>, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &Context<'_>, + cx: &Context<'_, '_>, ) -> fmt::Result { let amp = if f.alternate() { "&" } else { "&" }; @@ -1724,7 +1520,7 @@ impl clean::FnDecl { } clean::SelfExplicit(ref typ) => { write!(f, "self: ")?; - typ.print(&ambiguity_table, cx).fmt(f)?; + typ.print(&cx).fmt(f)?; } } } else { @@ -1733,7 +1529,7 @@ impl clean::FnDecl { } write!(f, "{}: ", input.name)?; - fmt_type(&input.type_, f, false, &ambiguity_table, cx)?; + fmt_type(&input.type_, f, false, &cx)?; } } @@ -1749,27 +1545,26 @@ impl clean::FnDecl { Some(n) => write!(f, "\n{})", Indent(n))?, }; - self.print_output(&ambiguity_table, cx).fmt(f) + self.print_output(&cx).fmt(f) } - fn print_output<'a, 'tcx: 'a>( + fn print_output<'a, 'tcx: 'a, 'at: 'a>( &'a self, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match &self.output { clean::Tuple(tys) if tys.is_empty() => Ok(()), ty if f.alternate() => { - write!(f, " -> {:#}", ty.print(ambiguity_table, cx)) + write!(f, " -> {:#}", ty.print(cx)) } - ty => write!(f, " -> {}", ty.print(ambiguity_table, cx)), + ty => write!(f, " -> {}", ty.print(cx)), }) } } -pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>( +pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a, 'at: 'a>( item: &clean::Item, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'a + Captures<'tcx> { use std::fmt::Write as _; let vis: Cow<'static, str> = match item.visibility(cx.tcx()) { @@ -1821,7 +1616,7 @@ pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>( /// This function is the same as print_with_space, except that it renders no links. /// It's used for macros' rendered source view, which is syntax highlighted and cannot have /// any HTML in it. -pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a>( +pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a, 'at: 'a>( visibility: Option>, tcx: TyCtxt<'tcx>, item_did: DefId, @@ -1907,24 +1702,23 @@ pub(crate) fn print_constness_with_space( } impl clean::Import { - pub(crate) fn print<'a, 'tcx: 'a>( + pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( &'a self, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self.kind { clean::ImportKind::Simple(name) => { if name == self.source.path.last() { - write!(f, "use {};", self.source.print(ambiguity_table, cx)) + write!(f, "use {};", self.source.print(cx)) } else { - write!(f, "use {source} as {name};", source = self.source.print(ambiguity_table, cx)) + write!(f, "use {source} as {name};", source = self.source.print(cx)) } } clean::ImportKind::Glob => { if self.source.path.segments.is_empty() { write!(f, "use *;") } else { - write!(f, "use {}::*;", self.source.print(ambiguity_table, cx)) + write!(f, "use {}::*;", self.source.print(cx)) } } }) @@ -1932,13 +1726,12 @@ impl clean::Import { } impl clean::ImportSource { - pub(crate) fn print<'a, 'tcx: 'a>( + pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( &'a self, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self.did { - Some(did) => resolved_path(f, did, &self.path, true, false, ambiguity_table, cx), + Some(did) => resolved_path(f, did, &self.path, true, false, cx), _ => { for seg in &self.path.segments[..self.path.segments.len() - 1] { write!(f, "{}::", seg.name)?; @@ -1961,23 +1754,22 @@ impl clean::ImportSource { } impl clean::TypeBinding { - pub(crate) fn print<'a, 'tcx: 'a>( + pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( &'a self, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { f.write_str(self.assoc.name.as_str())?; - self.assoc.args.print(ambiguity_table, cx).fmt(f)?; + self.assoc.args.print(cx).fmt(f)?; match self.kind { clean::TypeBindingKind::Equality { ref term } => { f.write_str(" = ")?; - term.print(ambiguity_table, cx).fmt(f)?; + term.print(cx).fmt(f)?; } clean::TypeBindingKind::Constraint { ref bounds } => { if !bounds.is_empty() { f.write_str(": ")?; - print_generic_bounds(bounds, ambiguity_table, cx).fmt(f)?; + print_generic_bounds(bounds, cx).fmt(f)?; } } } @@ -2001,14 +1793,13 @@ pub(crate) fn print_default_space<'a>(v: bool) -> &'a str { } impl clean::GenericArg { - pub(crate) fn print<'a, 'tcx: 'a>( + pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( &'a self, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self { clean::GenericArg::Lifetime(lt) => lt.print().fmt(f), - clean::GenericArg::Type(ty) => ty.print(ambiguity_table, cx).fmt(f), + clean::GenericArg::Type(ty) => ty.print(cx).fmt(f), clean::GenericArg::Const(ct) => ct.print(cx.tcx()).fmt(f), clean::GenericArg::Infer => Display::fmt("_", f), }) @@ -2016,13 +1807,12 @@ impl clean::GenericArg { } impl clean::Term { - pub(crate) fn print<'a, 'tcx: 'a>( + pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( &'a self, - ambiguity_table: &'a AmbiguityTable<'_>, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self { - clean::Term::Type(ty) => ty.print(ambiguity_table, cx).fmt(f), + clean::Term::Type(ty) => ty.print(cx).fmt(f), clean::Term::Constant(ct) => ct.print(cx.tcx()).fmt(f), }) } diff --git a/src/librustdoc/html/mod.rs b/src/librustdoc/html/mod.rs index 481ed16c05f7e..b00a0679ff03b 100644 --- a/src/librustdoc/html/mod.rs +++ b/src/librustdoc/html/mod.rs @@ -1,5 +1,6 @@ pub(crate) mod escape; pub(crate) mod format; +mod ambiguity; pub(crate) mod highlight; pub(crate) mod layout; mod length_limit; diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index fc6f51e8272ae..53f3e201204c1 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -29,6 +29,7 @@ use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::formats::FormatRenderer; +use crate::html::ambiguity::AmbiguityTable; use crate::html::escape::Escape; use crate::html::format::{join_with_double_colon, Buffer}; use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap}; @@ -45,7 +46,7 @@ use askama::Template; /// It is intended that this context is a lightweight object which can be fairly /// easily cloned because it is cloned per work-job (about once per item in the /// rustdoc tree). -pub(crate) struct Context<'tcx> { +pub(crate) struct Context<'tcx, 'at> { /// Current hierarchy of components leading down to what's currently being /// rendered pub(crate) current: Vec, @@ -75,11 +76,13 @@ pub(crate) struct Context<'tcx> { pub(crate) types_with_notable_traits: FxHashSet, /// Field used during rendering, to know if we're inside an inlined item. pub(crate) is_inside_inlined_module: bool, + + pub(crate) ambiguity_table: AmbiguityTable<'at>, } // `Context` is cloned a lot, so we don't want the size to grow unexpectedly. #[cfg(all(not(windows), target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Context<'_>, 160); +rustc_data_structures::static_assert_size!(Context<'_, '_>, 192); /// Shared mutable state used in [`Context`] and elsewhere. pub(crate) struct SharedContext<'tcx> { @@ -149,7 +152,7 @@ impl SharedContext<'_> { } } -impl<'tcx> Context<'tcx> { +impl<'tcx, 'at> Context<'tcx, 'at> { pub(crate) fn tcx(&self) -> TyCtxt<'tcx> { self.shared.tcx } @@ -434,7 +437,7 @@ impl<'tcx> Context<'tcx> { } /// Generates the documentation for `crate` into the directory `dst` -impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { +impl<'tcx> FormatRenderer<'tcx> for Context<'tcx, '_> { fn descr() -> &'static str { "html" } @@ -567,6 +570,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { include_sources, types_with_notable_traits: FxHashSet::default(), is_inside_inlined_module: false, + ambiguity_table: AmbiguityTable::empty(), }; if emit_crate { @@ -597,6 +601,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { include_sources: self.include_sources, types_with_notable_traits: FxHashSet::default(), is_inside_inlined_module: self.is_inside_inlined_module, + ambiguity_table: self.ambiguity_table.clone() } } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index f1887684797a6..092d62307b39a 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -533,8 +533,8 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String { ) } -fn document<'a, 'cx: 'a>( - cx: &'a mut Context<'cx>, +fn document<'a, 'cx: 'a, 'at: 'a>( + cx: &'a mut Context<'cx, 'at>, item: &'a clean::Item, parent: Option<&'a clean::Item>, heading_offset: HeadingOffset, @@ -1443,7 +1443,7 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> } } -pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> Option { +pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_, '_>) -> Option { let mut has_notable_trait = false; if ty.is_unit() { diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 5d4f1acc4b188..f0dd45e6c8ecd 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -25,7 +25,8 @@ use super::{ use crate::clean; use crate::config::ModuleSorting; use crate::formats::item_type::ItemType; -use crate::formats::Impl; +use crate::formats::{FormatRenderer, Impl}; +use crate::html::ambiguity::AmbiguityTable; use crate::html::escape::Escape; use crate::html::format::{ display_fn, join_with_double_colon, print_abi_with_space, print_constness_with_space, @@ -70,8 +71,8 @@ macro_rules! item_template { ) => { #[derive(Template)] $(#[$meta])* - struct $name<'a, 'cx> { - cx: RefCell<&'a mut Context<'cx>>, + struct $name<'a, 'cx, 'at> { + cx: RefCell<&'a mut Context<'cx, 'at>>, it: &'a clean::Item, $($field_name: $field_ty),* } @@ -168,10 +169,10 @@ struct ItemVars<'a> { } /// Calls `print_where_clause` and returns `true` if a `where` clause was generated. -fn print_where_clause_and_check<'a, 'tcx: 'a>( +fn print_where_clause_and_check<'a, 'tcx: 'a, 'at: 'a>( buffer: &mut Buffer, gens: &'a clean::Generics, - cx: &'a Context<'tcx>, + cx: &'a Context<'tcx, 'at>, ) -> bool { let len_before = buffer.len(); write!(buffer, "{}", print_where_clause(gens, cx, 0, Ending::Newline)); @@ -179,7 +180,7 @@ fn print_where_clause_and_check<'a, 'tcx: 'a>( } pub(super) fn print_item( - cx: &mut Context<'_>, + cx: &mut Context<'_, '_>, item: &clean::Item, buf: &mut Buffer, page: &Page<'_>, @@ -320,8 +321,8 @@ fn toggle_close(mut w: impl fmt::Write) { w.write_str("").unwrap(); } -trait ItemTemplate<'a, 'cx: 'a>: askama::Template + fmt::Display { - fn item_and_mut_cx(&self) -> (&'a clean::Item, RefMut<'_, &'a mut Context<'cx>>); +trait ItemTemplate<'a, 'cx: 'a, 'at: 'a>: askama::Template + fmt::Display { + fn item_and_mut_cx(&self) -> (&'a clean::Item, RefMut<'_, &'a mut Context<'cx, 'at>>); } fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: &[clean::Item]) { @@ -624,7 +625,7 @@ fn extra_info_tags<'a, 'tcx: 'a>( }) } -fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &clean::Function) { +fn item_function(w: &mut Buffer, cx: &mut Context<'_,'_>, it: &clean::Item, f: &clean::Function) { let tcx = cx.tcx(); let header = it.fn_header(tcx).expect("printing a function which isn't a function"); let constness = print_constness_with_space(&header.constness, it.const_stability(tcx)); @@ -645,7 +646,10 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle + generics_len; let notable_traits = notable_traits_button(&f.decl.output, cx); - + let mut child_cx = cx.make_child_renderer(); + assert!(child_cx.ambiguity_table.is_empty()); + let amb_table = AmbiguityTable::build().add_fn(f).finnish(); + child_cx.ambiguity_table = amb_table; wrap_item(w, |w| { w.reserve(header_len); write!( From 268e468215b861faf4eb252eb0f48234209ba66e Mon Sep 17 00:00:00 2001 From: Arthur Carcano Date: Fri, 29 Mar 2024 18:32:41 +0100 Subject: [PATCH 6/6] wip --- src/librustdoc/html/ambiguity.rs | 42 +-- src/librustdoc/html/format.rs | 293 ++++++++++++--------- src/librustdoc/html/mod.rs | 2 +- src/librustdoc/html/render/context.rs | 13 +- src/librustdoc/html/render/mod.rs | 65 +++-- src/librustdoc/html/render/print_item.rs | 133 ++++++---- src/librustdoc/html/render/sidebar.rs | 10 +- src/librustdoc/html/render/write_shared.rs | 8 +- src/librustdoc/lib.rs | 1 + tests/rustdoc/fn_param_ambiguities.rs | 2 +- 10 files changed, 325 insertions(+), 244 deletions(-) diff --git a/src/librustdoc/html/ambiguity.rs b/src/librustdoc/html/ambiguity.rs index cf50497debdac..4a4dc5928473b 100644 --- a/src/librustdoc/html/ambiguity.rs +++ b/src/librustdoc/html/ambiguity.rs @@ -1,4 +1,3 @@ -#![allow(warnings)] use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_span::Symbol; @@ -14,7 +13,7 @@ pub struct PathLike<'a> { impl<'a> PathLike<'a> { pub fn make_longer(self) -> Self { let Self { path, suffix_len } = self; - assert!(suffix_len < path.segments.len()); + assert!(suffix_len < path.segments.len(), "{self:?}"); Self { path, suffix_len: suffix_len + 1 } } @@ -30,7 +29,7 @@ impl<'a> PartialEq for PathLike<'a> { return false; } let self_suffix = self.iter_from_end(); - let other_suffix = self.iter_from_end(); + let other_suffix = other.iter_from_end(); self_suffix.zip(other_suffix).all(|(s, o)| s.eq(o)) } } @@ -53,17 +52,30 @@ impl<'a> AmbiguityTable<'a> { Self { inner: FxHashMap::default() } } - pub fn is_empty(&self) -> bool { - self.inner.is_empty() - } + // pub fn is_empty(&self) -> bool { + // self.inner.is_empty() + // } pub fn build() -> AmbiguityTableBuilder<'a> { AmbiguityTableBuilder { inner: FxHashMap::default() } } + #[allow(rustc::pass_by_value)] pub fn get(&self, x: &DefId) -> Option<&PathLike<'a>> { self.inner.get(x) } + + pub fn build_fn_decl(decl: &'a FnDecl) -> Self { + let mut builder = Self::build(); + builder.add_fndecl(decl); + builder.finnish() + } + + pub fn build_fn(f: &'a Function) -> Self { + let mut builder = Self::build(); + builder.add_fn(f); + builder.finnish() + } } enum AmbiguityTableBuilderEntry { @@ -79,19 +91,21 @@ impl<'a> AmbiguityTableBuilder<'a> { // Invariant: must start with length 1 path view fn add_path_view(&mut self, p: PathLike<'a>, did: DefId) { use std::collections::hash_map::Entry::*; - // TODO: clone match self.inner.entry(p.clone()) { Occupied(entry) => { - let v = - std::mem::replace(entry.into_mut(), AmbiguityTableBuilderEntry::IsAmbiguous); - let p = p.make_longer(); + match entry.get() { + AmbiguityTableBuilderEntry::MapsToOne(other_did) if other_did == &did => return, + _ => (), + } + let (other_p, v) = entry.replace_entry(AmbiguityTableBuilderEntry::IsAmbiguous); + // dbg!(&other_p, &p); match v { AmbiguityTableBuilderEntry::MapsToOne(other_did) => { - self.add_path_view(p.clone(), other_did) + self.add_path_view(other_p.make_longer(), other_did) } AmbiguityTableBuilderEntry::IsAmbiguous => (), } - self.add_path_view(p.clone(), did) + self.add_path_view(p.make_longer(), did) } Vacant(entry) => { entry.insert(AmbiguityTableBuilderEntry::MapsToOne(did)); @@ -112,7 +126,6 @@ impl<'a> AmbiguityTableBuilder<'a> { } fn add_poly_trait(&mut self, poly_trait: &'a clean::PolyTrait) { - // TODO: also add potential bounds on trait parameters self.add_path(&poly_trait.trait_); for gen_param in &poly_trait.generic_params { use clean::GenericParamDefKind::*; @@ -172,9 +185,8 @@ impl<'a> AmbiguityTableBuilder<'a> { self.add_type(&decl.output); } - pub fn add_fn(mut self, f: &'a Function) -> Self{ + pub fn add_fn(&mut self, f: &'a Function) { self.add_fndecl(&f.decl); - self } pub fn finnish(self) -> AmbiguityTable<'a> { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index ab1c43f638682..e2850a29fbdaa 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -37,6 +37,7 @@ use crate::html::escape::Escape; use crate::html::render::Context; use crate::passes::collect_intra_doc_links::UrlFragment; +use super::ambiguity::AmbiguityTable; use super::url_parts_builder::estimate_item_path_byte_length; use super::url_parts_builder::UrlPartsBuilder; @@ -164,9 +165,10 @@ pub(crate) fn comma_sep( }) } -pub(crate) fn print_generic_bounds<'a, 'tcx: 'a, 'at: 'a>( +pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>( bounds: &'a [clean::GenericBound], - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { let mut bounds_dup = FxHashSet::default(); @@ -175,16 +177,17 @@ pub(crate) fn print_generic_bounds<'a, 'tcx: 'a, 'at: 'a>( if i > 0 { f.write_str(" + ")?; } - bound.print(cx).fmt(f)?; + bound.print(cx, at).fmt(f)?; } Ok(()) }) } impl clean::GenericParamDef { - pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( + pub(crate) fn print<'a, 'tcx: 'a>( &'a self, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match &self.kind { clean::GenericParamDefKind::Lifetime { outlives } => { @@ -207,19 +210,19 @@ impl clean::GenericParamDef { if !bounds.is_empty() { f.write_str(": ")?; - print_generic_bounds(bounds, cx).fmt(f)?; + print_generic_bounds(bounds, cx, at).fmt(f)?; } if let Some(ref ty) = default { f.write_str(" = ")?; - ty.print(cx).fmt(f)?; + ty.print(cx, at).fmt(f)?; } Ok(()) } clean::GenericParamDefKind::Const { ty, default, .. } => { write!(f, "const {}: ", self.name)?; - ty.print(cx).fmt(f)?; + ty.print(cx, at).fmt(f)?; if let Some(default) = default { f.write_str(" = ")?; @@ -237,9 +240,10 @@ impl clean::GenericParamDef { } impl clean::Generics { - pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( + pub(crate) fn print<'a, 'tcx: 'a>( &'a self, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable(); @@ -248,9 +252,9 @@ impl clean::Generics { } if f.alternate() { - write!(f, "<{:#}>", comma_sep(real_params.map(|g| g.print(cx)), true)) + write!(f, "<{:#}>", comma_sep(real_params.map(|g| g.print(cx, at)), true)) } else { - write!(f, "<{}>", comma_sep(real_params.map(|g| g.print(cx)), true)) + write!(f, "<{}>", comma_sep(real_params.map(|g| g.print(cx, at)), true)) } }) } @@ -265,9 +269,10 @@ pub(crate) enum Ending { /// * The Generics from which to emit a where-clause. /// * The number of spaces to indent each line with. /// * Whether the where-clause needs to add a comma and newline after the last bound. -pub(crate) fn print_where_clause<'a, 'tcx: 'a, 'at: 'a>( +pub(crate) fn print_where_clause<'a, 'tcx: 'a>( gens: &'a clean::Generics, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, indent: usize, ending: Ending, ) -> impl Display + 'a + Captures<'tcx> { @@ -285,12 +290,12 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a, 'at: 'a>( match pred { clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => { - print_higher_ranked_params_with_space(bound_params, cx).fmt(f)?; - ty.print(cx).fmt(f)?; + print_higher_ranked_params_with_space(bound_params, cx, at).fmt(f)?; + ty.print(cx, at).fmt(f)?; f.write_str(":")?; if !bounds.is_empty() { f.write_str(" ")?; - print_generic_bounds(bounds, cx).fmt(f)?; + print_generic_bounds(bounds, cx, at).fmt(f)?; } Ok(()) } @@ -299,15 +304,15 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a, 'at: 'a>( // the lifetime nor the bounds contain any characters which need escaping. write!(f, "{}:", lifetime.print())?; if !bounds.is_empty() { - write!(f, " {}", print_generic_bounds(bounds, cx))?; + write!(f, " {}", print_generic_bounds(bounds, cx, at))?; } Ok(()) } clean::WherePredicate::EqPredicate { lhs, rhs } => { if f.alternate() { - write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx)) + write!(f, "{:#} == {:#}", lhs.print(cx, at), rhs.print(cx, at)) } else { - write!(f, "{} == {}", lhs.print(cx), rhs.print(cx)) + write!(f, "{} == {}", lhs.print(cx, at), rhs.print(cx, at)) } } } @@ -387,18 +392,23 @@ impl clean::Constant { } impl clean::PolyTrait { - fn print<'a, 'tcx: 'a, 'at: 'a>(&'a self, cx: &'a Context<'tcx, 'at>) -> impl Display + 'a + Captures<'tcx> { + fn print<'a, 'tcx: 'a>( + &'a self, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, + ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { - print_higher_ranked_params_with_space(&self.generic_params, cx).fmt(f)?; - self.trait_.print(cx).fmt(f) + print_higher_ranked_params_with_space(&self.generic_params, cx, at).fmt(f)?; + self.trait_.print(cx, at).fmt(f) }) } } impl clean::GenericBound { - pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( + pub(crate) fn print<'a, 'tcx: 'a>( &'a self, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self { clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()), @@ -410,14 +420,18 @@ impl clean::GenericBound { // `const` and `~const` trait bounds are experimental; don't render them. hir::TraitBoundModifier::Const | hir::TraitBoundModifier::MaybeConst => "", })?; - ty.print(cx).fmt(f) + ty.print(cx, at).fmt(f) } }) } } impl clean::GenericArgs { - fn print<'a, 'tcx: 'a, 'at: 'a>(&'a self, cx: &'a Context<'tcx, 'at>) -> impl Display + 'a + Captures<'tcx> { + fn print<'a, 'tcx: 'a>( + &'a self, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, + ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { match self { clean::GenericArgs::AngleBracketed { args, bindings } => { @@ -434,9 +448,9 @@ impl clean::GenericArgs { } comma = true; if f.alternate() { - write!(f, "{:#}", arg.print(cx))?; + write!(f, "{:#}", arg.print(cx, at))?; } else { - write!(f, "{}", arg.print(cx))?; + write!(f, "{}", arg.print(cx, at))?; } } for binding in bindings.iter() { @@ -445,9 +459,9 @@ impl clean::GenericArgs { } comma = true; if f.alternate() { - write!(f, "{:#}", binding.print(cx))?; + write!(f, "{:#}", binding.print(cx, at))?; } else { - write!(f, "{}", binding.print(cx))?; + write!(f, "{}", binding.print(cx, at))?; } } if f.alternate() { @@ -465,14 +479,14 @@ impl clean::GenericArgs { f.write_str(", ")?; } comma = true; - ty.print(cx).fmt(f)?; + ty.print(cx, at).fmt(f)?; } f.write_str(")")?; if let Some(ref ty) = *output { if f.alternate() { - write!(f, " -> {:#}", ty.print(cx))?; + write!(f, " -> {:#}", ty.print(cx, at))?; } else { - write!(f, " -> {}", ty.print(cx))?; + write!(f, " -> {}", ty.print(cx, at))?; } } } @@ -525,7 +539,7 @@ pub(crate) fn join_with_double_colon(syms: &[Symbol]) -> String { /// `href_with_root_path`. fn generate_macro_def_id_path( def_id: DefId, - cx: &Context<'_, '_>, + cx: &Context<'_>, root_path: Option<&str>, ) -> Result<(String, ItemType, Vec), HrefError> { let tcx = cx.tcx(); @@ -590,7 +604,7 @@ fn generate_macro_def_id_path( fn generate_item_def_id_path( mut def_id: DefId, original_def_id: DefId, - cx: &Context<'_, '_>, + cx: &Context<'_>, root_path: Option<&str>, original_def_kind: DefKind, ) -> Result<(String, ItemType, Vec), HrefError> { @@ -683,7 +697,7 @@ fn make_href( pub(crate) fn href_with_root_path( original_did: DefId, - cx: &Context<'_, '_>, + cx: &Context<'_>, root_path: Option<&str>, ) -> Result<(String, ItemType, Vec), HrefError> { let tcx = cx.tcx(); @@ -753,7 +767,7 @@ pub(crate) fn href_with_root_path( pub(crate) fn href( did: DefId, - cx: &Context<'_, '_>, + cx: &Context<'_>, ) -> Result<(String, ItemType, Vec), HrefError> { href_with_root_path(did, cx, None) } @@ -790,7 +804,7 @@ pub(crate) fn href_relative_parts<'fqp>( } } -pub(crate) fn link_tooltip(did: DefId, fragment: &Option, cx: &Context<'_, '_>,) -> String { +pub(crate) fn link_tooltip(did: DefId, fragment: &Option, cx: &Context<'_>) -> String { let cache = cx.cache(); let Some((fqp, shortty)) = cache.paths.get(&did).or_else(|| cache.external_paths.get(&did)) else { @@ -826,7 +840,8 @@ fn resolved_path<'cx>( path: &clean::Path, print_all: bool, use_absolute: bool, - cx: &'cx Context<'_, '_>, + cx: &'cx Context<'_>, + at: &AmbiguityTable<'_>, ) -> fmt::Result { let last = path.segments.last().unwrap(); @@ -836,7 +851,7 @@ fn resolved_path<'cx>( } } if w.alternate() { - write!(w, "{}{:#}", &last.name, last.args.print(cx))?; + write!(w, "{}{:#}", &last.name, last.args.print(cx, at))?; } else { let path = if use_absolute { if let Ok((_, _, fqp)) = href(did, cx) { @@ -849,7 +864,7 @@ fn resolved_path<'cx>( last.name.to_string() } } else { - match cx.ambiguity_table.get(&did) { + match at.get(&did) { Some(path_view) => { let mut iter = path_view.iter_from_end(); let end = iter.next().unwrap(); @@ -861,7 +876,7 @@ fn resolved_path<'cx>( None => anchor(did, last.name, cx).to_string(), } }; - write!(w, "{path}{args}", args = last.args.print(cx))?; + write!(w, "{path}{args}", args = last.args.print(cx, at))?; } Ok(()) } @@ -870,7 +885,7 @@ fn primitive_link( f: &mut fmt::Formatter<'_>, prim: clean::PrimitiveType, name: fmt::Arguments<'_>, - cx: &Context<'_, '_>, + cx: &Context<'_>, ) -> fmt::Result { primitive_link_fragment(f, prim, name, "", cx) } @@ -880,7 +895,7 @@ fn primitive_link_fragment( prim: clean::PrimitiveType, name: fmt::Arguments<'_>, fragment: &str, - cx: &Context<'_, '_>, + cx: &Context<'_>, ) -> fmt::Result { let m = &cx.cache(); let mut needs_termination = false; @@ -941,17 +956,18 @@ fn primitive_link_fragment( Ok(()) } -fn tybounds<'a, 'tcx: 'a, 'at: 'a>( +fn tybounds<'a, 'tcx: 'a>( bounds: &'a [clean::PolyTrait], lt: &'a Option, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { for (i, bound) in bounds.iter().enumerate() { if i > 0 { write!(f, " + ")?; } - bound.print(cx).fmt(f)?; + bound.print(cx, at).fmt(f)?; } if let Some(lt) = lt { // We don't need to check `alternate` since we can be certain that @@ -962,14 +978,15 @@ fn tybounds<'a, 'tcx: 'a, 'at: 'a>( }) } -fn print_higher_ranked_params_with_space<'a, 'tcx: 'a, 'at: 'a>( +fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>( params: &'a [clean::GenericParamDef], - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { if !params.is_empty() { f.write_str(if f.alternate() { "for<" } else { "for<" })?; - comma_sep(params.iter().map(|lt| lt.print(cx)), true).fmt(f)?; + comma_sep(params.iter().map(|lt| lt.print(cx, at)), true).fmt(f)?; f.write_str(if f.alternate() { "> " } else { "> " })?; } Ok(()) @@ -979,7 +996,7 @@ fn print_higher_ranked_params_with_space<'a, 'tcx: 'a, 'at: 'a>( pub(crate) fn anchor<'a, 'cx: 'a>( did: DefId, text: Symbol, - cx: &'cx Context<'_, '_>, + cx: &'cx Context<'_>, ) -> impl Display + 'a { let parts = href(did, cx); display_fn(move |f| { @@ -999,7 +1016,8 @@ fn fmt_type<'cx>( t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool, - cx: &'cx Context<'_, '_>, + cx: &'cx Context<'_>, + at: &AmbiguityTable<'_>, ) -> fmt::Result { trace!("fmt_type(t = {t:?})"); @@ -1008,11 +1026,11 @@ fn fmt_type<'cx>( clean::Type::Path { ref path } => { // Paths like `T::Output` and `Self::Output` should be rendered with all segments. let did = path.def_id(); - resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, cx) + resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, cx, at) } clean::DynTrait(ref bounds, ref lt) => { f.write_str("dyn ")?; - tybounds(bounds, lt, cx).fmt(f) + tybounds(bounds, lt, cx, at).fmt(f) } clean::Infer => write!(f, "_"), clean::Primitive(clean::PrimitiveType::Never) => { @@ -1022,7 +1040,7 @@ fn fmt_type<'cx>( primitive_link(f, prim, format_args!("{}", prim.as_sym().as_str()), cx) } clean::BareFunction(ref decl) => { - print_higher_ranked_params_with_space(&decl.generic_params, cx).fmt(f)?; + print_higher_ranked_params_with_space(&decl.generic_params, cx, at).fmt(f)?; decl.unsafety.print_with_space().fmt(f)?; print_abi_with_space(decl.abi).fmt(f)?; if f.alternate() { @@ -1030,7 +1048,7 @@ fn fmt_type<'cx>( } else { primitive_link(f, PrimitiveType::Fn, format_args!("fn"), cx)?; } - decl.decl.print(cx).fmt(f) + decl.decl.print(cx, at).fmt(f) } clean::Tuple(ref typs) => match &typs[..] { &[] => primitive_link(f, PrimitiveType::Unit, format_args!("()"), cx), @@ -1039,7 +1057,7 @@ fn fmt_type<'cx>( primitive_link(f, PrimitiveType::Tuple, format_args!("({name},)"), cx) } else { write!(f, "(")?; - one.print(cx).fmt(f)?; + one.print(cx, at).fmt(f)?; write!(f, ",)") } } @@ -1065,7 +1083,7 @@ fn fmt_type<'cx>( if i != 0 { write!(f, ", ")?; } - item.print(cx).fmt(f)?; + item.print(cx, at).fmt(f)?; } write!(f, ")") } @@ -1077,7 +1095,7 @@ fn fmt_type<'cx>( } _ => { write!(f, "[")?; - t.print(cx).fmt(f)?; + t.print(cx, at).fmt(f)?; write!(f, "]") } }, @@ -1090,7 +1108,7 @@ fn fmt_type<'cx>( ), _ => { write!(f, "[")?; - t.print(cx).fmt(f)?; + t.print(cx, at).fmt(f)?; if f.alternate() { write!(f, "; {n}")?; } else { @@ -1112,7 +1130,7 @@ fn fmt_type<'cx>( }; if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() { - let ty = t.print(cx); + let ty = t.print(cx, at); if f.alternate() { primitive_link( f, @@ -1130,7 +1148,7 @@ fn fmt_type<'cx>( } } else { primitive_link(f, clean::PrimitiveType::RawPointer, format_args!("*{m} "), cx)?; - t.print(cx).fmt(f) + t.print(cx, at).fmt(f) } } clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => { @@ -1164,7 +1182,7 @@ fn fmt_type<'cx>( if needs_parens { f.write_str("(")?; } - fmt_type(ty, f, use_absolute, cx)?; + fmt_type(ty, f, use_absolute, cx, at)?; if needs_parens { f.write_str(")")?; } @@ -1172,7 +1190,7 @@ fn fmt_type<'cx>( } clean::ImplTrait(ref bounds) => { f.write_str("impl ")?; - print_generic_bounds(bounds, cx).fmt(f) + print_generic_bounds(bounds, cx, at).fmt(f) } clean::QPath(box clean::QPathData { ref assoc, @@ -1187,17 +1205,17 @@ fn fmt_type<'cx>( if let Some(trait_) = trait_ && should_show_cast { - write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))? + write!(f, "<{:#} as {:#}>::", self_type.print(cx, at), trait_.print(cx, at))? } else { - write!(f, "{:#}::", self_type.print(cx))? + write!(f, "{:#}::", self_type.print(cx, at))? } } else { if let Some(trait_) = trait_ && should_show_cast { - write!(f, "<{} as {}>::", self_type.print(cx), trait_.print(cx))? + write!(f, "<{} as {}>::", self_type.print(cx, at), trait_.print(cx, at))? } else { - write!(f, "{}::", self_type.print(cx))? + write!(f, "{}::", self_type.print(cx, at))? } }; // It's pretty unsightly to look at `::C` in output, and @@ -1244,38 +1262,41 @@ fn fmt_type<'cx>( write!(f, "{}", assoc.name) }?; - assoc.args.print(cx).fmt(f) + assoc.args.print(cx, at).fmt(f) } } } impl clean::Type { - pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a, 'at: 'a>( + pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>( &'a self, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, ) -> impl Display + 'b + Captures<'tcx> { - display_fn(move |f| fmt_type(self, f, false, cx)) + display_fn(move |f| fmt_type(self, f, false, cx, at)) } } impl clean::Path { - pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a, 'at: 'a>( + pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>( &'a self, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'b AmbiguityTable<'_>, ) -> impl Display + 'b + Captures<'tcx> { - display_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx)) + display_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx, at)) } } impl clean::Impl { - pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( + pub(crate) fn print<'a, 'tcx: 'a>( &'a self, use_absolute: bool, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { f.write_str("impl")?; - self.generics.print(cx).fmt(f)?; + self.generics.print(cx, at).fmt(f)?; f.write_str(" ")?; if let Some(ref ty) = self.trait_ { @@ -1283,7 +1304,7 @@ impl clean::Impl { ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => {} ty::ImplPolarity::Negative => write!(f, "!")?, } - ty.print(cx).fmt(f)?; + ty.print(cx, at).fmt(f)?; write!(f, " for ")?; } @@ -1308,7 +1329,7 @@ impl clean::Impl { // Hardcoded anchor library/core/src/primitive_docs.rs // Link should match `# Trait implementations` - print_higher_ranked_params_with_space(&bare_fn.generic_params, cx).fmt(f)?; + print_higher_ranked_params_with_space(&bare_fn.generic_params, cx, at).fmt(f)?; bare_fn.unsafety.print_with_space().fmt(f)?; print_abi_with_space(bare_fn.abi).fmt(f)?; let ellipsis = if bare_fn.decl.c_variadic { ", ..." } else { "" }; @@ -1322,28 +1343,29 @@ impl clean::Impl { // Write output. if !bare_fn.decl.output.is_unit() { write!(f, " -> ")?; - fmt_type(&bare_fn.decl.output, f, use_absolute, cx)?; + fmt_type(&bare_fn.decl.output, f, use_absolute, cx, at)?; } } else if let Some(ty) = self.kind.as_blanket_ty() { - fmt_type(ty, f, use_absolute, cx)?; + fmt_type(ty, f, use_absolute, cx, at)?; } else { - fmt_type(&self.for_, f, use_absolute, cx)?; + fmt_type(&self.for_, f, use_absolute, cx, at)?; } - print_where_clause(&self.generics, cx, 0, Ending::Newline).fmt(f) + print_where_clause(&self.generics, cx, at, 0, Ending::Newline).fmt(f) }) } } impl clean::Arguments { - pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( + pub(crate) fn print<'a, 'tcx: 'a>( &'a self, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { for (i, input) in self.values.iter().enumerate() { write!(f, "{}: ", input.name)?; - input.type_.print(cx).fmt(f)?; + input.type_.print(cx, at).fmt(f)?; if i + 1 < self.values.len() { write!(f, ", ")?; } @@ -1376,9 +1398,10 @@ impl Display for Indent { } impl clean::FnDecl { - pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a, 'at: 'a>( + pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>( &'a self, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'b AmbiguityTable<'_>, ) -> impl Display + 'b + Captures<'tcx> { display_fn(move |f| { let ellipsis = if self.c_variadic { ", ..." } else { "" }; @@ -1386,17 +1409,17 @@ impl clean::FnDecl { write!( f, "({args:#}{ellipsis}){arrow:#}", - args = self.inputs.print(cx), + args = self.inputs.print(cx, at), ellipsis = ellipsis, - arrow = self.print_output(cx) + arrow = self.print_output(cx, at) ) } else { write!( f, "({args}{ellipsis}){arrow}", - args = self.inputs.print(cx), + args = self.inputs.print(cx, at), ellipsis = ellipsis, - arrow = self.print_output(cx) + arrow = self.print_output(cx, at) ) } }) @@ -1408,23 +1431,28 @@ impl clean::FnDecl { /// are preserved. /// * `indent`: The number of spaces to indent each successive line with, if line-wrapping is /// necessary. - pub(crate) fn full_print<'a, 'tcx: 'a, 'at: 'a>( + pub(crate) fn full_print<'a, 'tcx: 'a>( &'a self, header_len: usize, indent: usize, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { // First, generate the text form of the declaration, with no line wrapping, and count the bytes. let mut counter = WriteCounter(0); - write!(&mut counter, "{:#}", display_fn(|f| { self.inner_full_print(None, f, cx) })) - .unwrap(); + write!( + &mut counter, + "{:#}", + display_fn(|f| { self.inner_full_print(None, f, cx, at) }) + ) + .unwrap(); // If the text form was over 80 characters wide, we will line-wrap our output. let line_wrapping_indent = if header_len + counter.0 > 80 { Some(indent) } else { None }; // Generate the final output. This happens to accept `{:#}` formatting to get textual // output but in practice it is only formatted with `{}` to get HTML output. - self.inner_full_print(line_wrapping_indent, f, cx) + self.inner_full_print(line_wrapping_indent, f, cx, at) }) } @@ -1481,7 +1509,8 @@ impl clean::FnDecl { // the declaration will be line-wrapped, with an indent of n spaces. line_wrapping_indent: Option, f: &mut fmt::Formatter<'_>, - cx: &Context<'_, '_>, + cx: &Context<'_>, + at: &AmbiguityTable<'_>, ) -> fmt::Result { let amp = if f.alternate() { "&" } else { "&" }; @@ -1520,7 +1549,7 @@ impl clean::FnDecl { } clean::SelfExplicit(ref typ) => { write!(f, "self: ")?; - typ.print(&cx).fmt(f)?; + typ.print(&cx, at).fmt(f)?; } } } else { @@ -1529,7 +1558,7 @@ impl clean::FnDecl { } write!(f, "{}: ", input.name)?; - fmt_type(&input.type_, f, false, &cx)?; + fmt_type(&input.type_, f, false, &cx, at)?; } } @@ -1545,26 +1574,27 @@ impl clean::FnDecl { Some(n) => write!(f, "\n{})", Indent(n))?, }; - self.print_output(&cx).fmt(f) + self.print_output(&cx, at).fmt(f) } - fn print_output<'a, 'tcx: 'a, 'at: 'a>( + fn print_output<'a, 'tcx: 'a>( &'a self, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match &self.output { clean::Tuple(tys) if tys.is_empty() => Ok(()), ty if f.alternate() => { - write!(f, " -> {:#}", ty.print(cx)) + write!(f, " -> {:#}", ty.print(cx, at)) } - ty => write!(f, " -> {}", ty.print(cx)), + ty => write!(f, " -> {}", ty.print(cx, at)), }) } } -pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a, 'at: 'a>( +pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>( item: &clean::Item, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { use std::fmt::Write as _; let vis: Cow<'static, str> = match item.visibility(cx.tcx()) { @@ -1616,7 +1646,7 @@ pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a, 'at: 'a>( /// This function is the same as print_with_space, except that it renders no links. /// It's used for macros' rendered source view, which is syntax highlighted and cannot have /// any HTML in it. -pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a, 'at: 'a>( +pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a>( visibility: Option>, tcx: TyCtxt<'tcx>, item_did: DefId, @@ -1702,23 +1732,24 @@ pub(crate) fn print_constness_with_space( } impl clean::Import { - pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( + pub(crate) fn print<'a, 'tcx: 'a>( &'a self, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self.kind { clean::ImportKind::Simple(name) => { if name == self.source.path.last() { - write!(f, "use {};", self.source.print(cx)) + write!(f, "use {};", self.source.print(cx, at)) } else { - write!(f, "use {source} as {name};", source = self.source.print(cx)) + write!(f, "use {source} as {name};", source = self.source.print(cx, at)) } } clean::ImportKind::Glob => { if self.source.path.segments.is_empty() { write!(f, "use *;") } else { - write!(f, "use {}::*;", self.source.print(cx)) + write!(f, "use {}::*;", self.source.print(cx, at)) } } }) @@ -1726,12 +1757,13 @@ impl clean::Import { } impl clean::ImportSource { - pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( + pub(crate) fn print<'a, 'tcx: 'a>( &'a self, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self.did { - Some(did) => resolved_path(f, did, &self.path, true, false, cx), + Some(did) => resolved_path(f, did, &self.path, true, false, cx, at), _ => { for seg in &self.path.segments[..self.path.segments.len() - 1] { write!(f, "{}::", seg.name)?; @@ -1754,22 +1786,23 @@ impl clean::ImportSource { } impl clean::TypeBinding { - pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( + pub(crate) fn print<'a, 'tcx: 'a>( &'a self, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| { f.write_str(self.assoc.name.as_str())?; - self.assoc.args.print(cx).fmt(f)?; + self.assoc.args.print(cx, at).fmt(f)?; match self.kind { clean::TypeBindingKind::Equality { ref term } => { f.write_str(" = ")?; - term.print(cx).fmt(f)?; + term.print(cx, at).fmt(f)?; } clean::TypeBindingKind::Constraint { ref bounds } => { if !bounds.is_empty() { f.write_str(": ")?; - print_generic_bounds(bounds, cx).fmt(f)?; + print_generic_bounds(bounds, cx, at).fmt(f)?; } } } @@ -1793,13 +1826,14 @@ pub(crate) fn print_default_space<'a>(v: bool) -> &'a str { } impl clean::GenericArg { - pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( + pub(crate) fn print<'a, 'tcx: 'a>( &'a self, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self { clean::GenericArg::Lifetime(lt) => lt.print().fmt(f), - clean::GenericArg::Type(ty) => ty.print(cx).fmt(f), + clean::GenericArg::Type(ty) => ty.print(cx, at).fmt(f), clean::GenericArg::Const(ct) => ct.print(cx.tcx()).fmt(f), clean::GenericArg::Infer => Display::fmt("_", f), }) @@ -1807,12 +1841,13 @@ impl clean::GenericArg { } impl clean::Term { - pub(crate) fn print<'a, 'tcx: 'a, 'at: 'a>( + pub(crate) fn print<'a, 'tcx: 'a>( &'a self, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self { - clean::Term::Type(ty) => ty.print(cx).fmt(f), + clean::Term::Type(ty) => ty.print(cx, at).fmt(f), clean::Term::Constant(ct) => ct.print(cx.tcx()).fmt(f), }) } diff --git a/src/librustdoc/html/mod.rs b/src/librustdoc/html/mod.rs index b00a0679ff03b..2a7835c13cfe5 100644 --- a/src/librustdoc/html/mod.rs +++ b/src/librustdoc/html/mod.rs @@ -1,6 +1,6 @@ +mod ambiguity; pub(crate) mod escape; pub(crate) mod format; -mod ambiguity; pub(crate) mod highlight; pub(crate) mod layout; mod length_limit; diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 53f3e201204c1..fc6f51e8272ae 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -29,7 +29,6 @@ use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::formats::FormatRenderer; -use crate::html::ambiguity::AmbiguityTable; use crate::html::escape::Escape; use crate::html::format::{join_with_double_colon, Buffer}; use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap}; @@ -46,7 +45,7 @@ use askama::Template; /// It is intended that this context is a lightweight object which can be fairly /// easily cloned because it is cloned per work-job (about once per item in the /// rustdoc tree). -pub(crate) struct Context<'tcx, 'at> { +pub(crate) struct Context<'tcx> { /// Current hierarchy of components leading down to what's currently being /// rendered pub(crate) current: Vec, @@ -76,13 +75,11 @@ pub(crate) struct Context<'tcx, 'at> { pub(crate) types_with_notable_traits: FxHashSet, /// Field used during rendering, to know if we're inside an inlined item. pub(crate) is_inside_inlined_module: bool, - - pub(crate) ambiguity_table: AmbiguityTable<'at>, } // `Context` is cloned a lot, so we don't want the size to grow unexpectedly. #[cfg(all(not(windows), target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Context<'_, '_>, 192); +rustc_data_structures::static_assert_size!(Context<'_>, 160); /// Shared mutable state used in [`Context`] and elsewhere. pub(crate) struct SharedContext<'tcx> { @@ -152,7 +149,7 @@ impl SharedContext<'_> { } } -impl<'tcx, 'at> Context<'tcx, 'at> { +impl<'tcx> Context<'tcx> { pub(crate) fn tcx(&self) -> TyCtxt<'tcx> { self.shared.tcx } @@ -437,7 +434,7 @@ impl<'tcx, 'at> Context<'tcx, 'at> { } /// Generates the documentation for `crate` into the directory `dst` -impl<'tcx> FormatRenderer<'tcx> for Context<'tcx, '_> { +impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { fn descr() -> &'static str { "html" } @@ -570,7 +567,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx, '_> { include_sources, types_with_notable_traits: FxHashSet::default(), is_inside_inlined_module: false, - ambiguity_table: AmbiguityTable::empty(), }; if emit_crate { @@ -601,7 +597,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx, '_> { include_sources: self.include_sources, types_with_notable_traits: FxHashSet::default(), is_inside_inlined_module: self.is_inside_inlined_module, - ambiguity_table: self.ambiguity_table.clone() } } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 092d62307b39a..6634fa8376f35 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -82,6 +82,8 @@ use crate::scrape_examples::{CallData, CallLocation}; use crate::try_none; use crate::DOC_RUST_LANG_ORG_CHANNEL; +use super::ambiguity::AmbiguityTable; + pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ { crate::html::format::display_fn(move |f| { if !v.ends_with('/') && !v.is_empty() { write!(f, "{v}/") } else { f.write_str(v) } @@ -533,8 +535,8 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String { ) } -fn document<'a, 'cx: 'a, 'at: 'a>( - cx: &'a mut Context<'cx, 'at>, +fn document<'a, 'cx: 'a>( + cx: &'a mut Context<'cx>, item: &'a clean::Item, parent: Option<&'a clean::Item>, heading_offset: HeadingOffset, @@ -878,6 +880,7 @@ fn assoc_const( indent: usize, cx: &Context<'_>, ) { + let at = AmbiguityTable::empty(); let tcx = cx.tcx(); write!( w, @@ -886,8 +889,8 @@ fn assoc_const( vis = visibility_print_with_space(it, cx), href = assoc_href_attr(it, link, cx), name = it.name.as_ref().unwrap(), - generics = generics.print(cx), - ty = ty.print(cx), + generics = generics.print(cx, &at), + ty = ty.print(cx, &at), ); if let Some(default) = default { w.write_str(" = "); @@ -899,7 +902,7 @@ fn assoc_const( // Find a way to print constants here without all that jazz. write!(w, "{}", Escape(&default.value(tcx).unwrap_or_else(|| default.expr(tcx)))); } - write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline)); + write!(w, "{}", print_where_clause(generics, cx, &at, indent, Ending::NoNewline)); } fn assoc_type( @@ -912,6 +915,7 @@ fn assoc_type( indent: usize, cx: &Context<'_>, ) { + let at = AmbiguityTable::empty(); write!( w, "{indent}{vis}type {name}{generics}", @@ -919,16 +923,16 @@ fn assoc_type( vis = visibility_print_with_space(it, cx), href = assoc_href_attr(it, link, cx), name = it.name.as_ref().unwrap(), - generics = generics.print(cx), + generics = generics.print(cx, &at), ); if !bounds.is_empty() { - write!(w, ": {}", print_generic_bounds(bounds, cx)) + write!(w, ": {}", print_generic_bounds(bounds, cx, &at)) } // Render the default before the where-clause which aligns with the new recommended style. See #89122. if let Some(default) = default { - write!(w, " = {}", default.print(cx)) + write!(w, " = {}", default.print(cx, &at)) } - write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline)); + write!(w, "{}", print_where_clause(generics, cx, &at, indent, Ending::NoNewline)); } fn assoc_method( @@ -946,6 +950,7 @@ fn assoc_method( let name = meth.name.as_ref().unwrap(); let vis = visibility_print_with_space(meth, cx).to_string(); let defaultness = print_default_space(meth.is_default()); + let at = AmbiguityTable::build_fn_decl(d); // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove // this condition. let constness = match render_mode { @@ -960,7 +965,7 @@ fn assoc_method( let href = assoc_href_attr(meth, link, cx); // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`. - let generics_len = format!("{:#}", g.print(cx)).len(); + let generics_len = format!("{:#}", g.print(cx, &at)).len(); let mut header_len = "fn ".len() + vis.len() + defaultness.len() @@ -996,10 +1001,10 @@ fn assoc_method( abi = abi, href = href, name = name, - generics = g.print(cx), - decl = d.full_print(header_len, indent, cx), + generics = g.print(cx, &at), + decl = d.full_print(header_len, indent, cx, &at), notable_traits = notable_traits.unwrap_or_default(), - where_clause = print_where_clause(g, cx, indent, end_newline), + where_clause = print_where_clause(g, cx, &at, indent, end_newline), ); } @@ -1288,6 +1293,7 @@ fn render_assoc_items_inner( what: AssocItemRender<'_>, derefs: &mut DefIdSet, ) { + let at = AmbiguityTable::empty(); info!("Documenting associated items of {:?}", containing_item.name); let shared = Rc::clone(&cx.shared); let cache = &shared.cache; @@ -1301,15 +1307,17 @@ fn render_assoc_items_inner( (RenderMode::Normal, "implementations-list".to_owned(), "") } AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => { - let id = - cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx)))); + let id = cx.derive_id(small_url_encode(format!( + "deref-methods-{:#}", + type_.print(cx, &at) + ))); let derived_id = cx.derive_id(&id); write_impl_section_heading( &mut tmp_buf, &format!( "Methods from {trait_}<Target = {type_}>", - trait_ = trait_.print(cx), - type_ = type_.print(cx), + trait_ = trait_.print(cx, &at), + type_ = type_.print(cx, &at), ), &id, ); @@ -1443,7 +1451,7 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> } } -pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_, '_>) -> Option { +pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> Option { let mut has_notable_trait = false; if ty.is_unit() { @@ -1480,12 +1488,12 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_, '_>) } } } - if has_notable_trait { + let at = AmbiguityTable::empty(); cx.types_with_notable_traits.insert(ty.clone()); Some(format!( " ", - ty = Escape(&format!("{:#}", ty.print(cx))), + ty = Escape(&format!("{:#}", ty.print(cx, &at))), )) } else { None @@ -1498,7 +1506,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { let did = ty.def_id(cx.cache()).expect("notable_traits_button already checked this"); let impls = cx.cache().impls.get(&did).expect("notable_traits_button already checked this"); - + let at = AmbiguityTable::empty(); for i in impls { let impl_ = i.inner_impl(); if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) { @@ -1515,11 +1523,11 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { &mut out, "

Notable traits for {}

\
",
-                        impl_.for_.print(cx)
+                        impl_.for_.print(cx, &at)
                     );
                 }
 
-                write!(&mut out, "
{}
", impl_.print(false, cx)); + write!(&mut out, "
{}
", impl_.print(false, cx, &at)); for it in &impl_.items { if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind { out.push_str("
"); @@ -1545,7 +1553,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { out.write_str("
"); } - (format!("{:#}", ty.print(cx)), out.into_inner()) + (format!("{:#}", ty.print(cx, &at)), out.into_inner()) } pub(crate) fn notable_traits_json<'a>( @@ -2016,9 +2024,9 @@ pub(crate) fn render_impl_summary( "§\

" ); - + let at = AmbiguityTable::empty(); if let Some(use_absolute) = use_absolute { - write!(w, "{}", inner_impl.print(use_absolute, cx)); + write!(w, "{}", inner_impl.print(use_absolute, cx, &at)); if show_def_docs { for it in &inner_impl.items { if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind { @@ -2038,7 +2046,7 @@ pub(crate) fn render_impl_summary( } } } else { - write!(w, "{}", inner_impl.print(false, cx)); + write!(w, "{}", inner_impl.print(false, cx, &at)); } w.write_str("

"); @@ -2144,9 +2152,10 @@ fn get_id_for_impl<'tcx>(tcx: TyCtxt<'tcx>, impl_id: ItemId) -> String { fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> { match *item.kind { clean::ItemKind::ImplItem(ref i) if i.trait_.is_some() => { + let at = AmbiguityTable::empty(); // Alternative format produces no URLs, // so this parameter does nothing. - Some((format!("{:#}", i.for_.print(cx)), get_id_for_impl(cx.tcx(), item.item_id))) + Some((format!("{:#}", i.for_.print(cx, &at)), get_id_for_impl(cx.tcx(), item.item_id))) } _ => None, } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index f0dd45e6c8ecd..b8ab61627f371 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -25,7 +25,7 @@ use super::{ use crate::clean; use crate::config::ModuleSorting; use crate::formats::item_type::ItemType; -use crate::formats::{FormatRenderer, Impl}; +use crate::formats::Impl; use crate::html::ambiguity::AmbiguityTable; use crate::html::escape::Escape; use crate::html::format::{ @@ -71,8 +71,8 @@ macro_rules! item_template { ) => { #[derive(Template)] $(#[$meta])* - struct $name<'a, 'cx, 'at> { - cx: RefCell<&'a mut Context<'cx, 'at>>, + struct $name<'a, 'cx> { + cx: RefCell<&'a mut Context<'cx>>, it: &'a clean::Item, $($field_name: $field_ty),* } @@ -169,18 +169,19 @@ struct ItemVars<'a> { } /// Calls `print_where_clause` and returns `true` if a `where` clause was generated. -fn print_where_clause_and_check<'a, 'tcx: 'a, 'at: 'a>( +fn print_where_clause_and_check<'a, 'tcx: 'a>( buffer: &mut Buffer, gens: &'a clean::Generics, - cx: &'a Context<'tcx, 'at>, + cx: &'a Context<'tcx>, + at: &'a AmbiguityTable<'_>, ) -> bool { let len_before = buffer.len(); - write!(buffer, "{}", print_where_clause(gens, cx, 0, Ending::Newline)); + write!(buffer, "{}", print_where_clause(gens, cx, at, 0, Ending::Newline)); len_before != buffer.len() } pub(super) fn print_item( - cx: &mut Context<'_, '_>, + cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buffer, page: &Page<'_>, @@ -321,8 +322,8 @@ fn toggle_close(mut w: impl fmt::Write) { w.write_str("").unwrap(); } -trait ItemTemplate<'a, 'cx: 'a, 'at: 'a>: askama::Template + fmt::Display { - fn item_and_mut_cx(&self) -> (&'a clean::Item, RefMut<'_, &'a mut Context<'cx, 'at>>); +trait ItemTemplate<'a, 'cx: 'a>: askama::Template + fmt::Display { + fn item_and_mut_cx(&self) -> (&'a clean::Item, RefMut<'_, &'a mut Context<'cx>>); } fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: &[clean::Item]) { @@ -462,6 +463,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: } clean::ImportItem(ref import) => { + let at = AmbiguityTable::empty(); let stab_tags = if let Some(import_def_id) = import.source.did { // Just need an item with the correct def_id and attrs let import_item = @@ -493,7 +495,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: \ {stab_tags_before}{stab_tags}{stab_tags_after}", vis = visibility_print_with_space(myitem, cx), - imp = import.print(cx), + imp = import.print(cx, &at), ); w.write_str(ITEM_TABLE_ROW_CLOSE); } @@ -625,7 +627,7 @@ fn extra_info_tags<'a, 'tcx: 'a>( }) } -fn item_function(w: &mut Buffer, cx: &mut Context<'_,'_>, it: &clean::Item, f: &clean::Function) { +fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &clean::Function) { let tcx = cx.tcx(); let header = it.fn_header(tcx).expect("printing a function which isn't a function"); let constness = print_constness_with_space(&header.constness, it.const_stability(tcx)); @@ -634,8 +636,9 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_,'_>, it: &clean::Item, f: & let asyncness = header.asyncness.print_with_space(); let visibility = visibility_print_with_space(it, cx).to_string(); let name = it.name.unwrap(); + let at = AmbiguityTable::build_fn(f); - let generics_len = format!("{:#}", f.generics.print(cx)).len(); + let generics_len = format!("{:#}", f.generics.print(cx, &at)).len(); let header_len = "fn ".len() + visibility.len() + constness.len() @@ -646,10 +649,6 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_,'_>, it: &clean::Item, f: & + generics_len; let notable_traits = notable_traits_button(&f.decl.output, cx); - let mut child_cx = cx.make_child_renderer(); - assert!(child_cx.ambiguity_table.is_empty()); - let amb_table = AmbiguityTable::build().add_fn(f).finnish(); - child_cx.ambiguity_table = amb_table; wrap_item(w, |w| { w.reserve(header_len); write!( @@ -663,9 +662,9 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_,'_>, it: &clean::Item, f: & unsafety = unsafety, abi = abi, name = name, - generics = f.generics.print(cx), - where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline), - decl = f.decl.full_print(header_len, 0, cx), + generics = f.generics.print(cx, &at), + where_clause = print_where_clause(&f.generics, cx, &at, 0, Ending::Newline), + decl = f.decl.full_print(header_len, 0, cx, &at), notable_traits = notable_traits.unwrap_or_default(), ); }); @@ -686,6 +685,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: let count_methods = required_methods.len() + provided_methods.len(); let must_implement_one_of_functions = tcx.trait_def(t.def_id).must_implement_one_of.clone(); + let at = AmbiguityTable::empty(); // Output the trait definition wrap_item(w, |mut w| { write!( @@ -696,11 +696,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: unsafety = t.unsafety(tcx).print_with_space(), is_auto = if t.is_auto(tcx) { "auto " } else { "" }, name = it.name.unwrap(), - generics = t.generics.print(cx), + generics = t.generics.print(cx, &at), ); if !t.generics.where_predicates.is_empty() { - write!(w, "{}", print_where_clause(&t.generics, cx, 0, Ending::Newline)); + write!(w, "{}", print_where_clause(&t.generics, cx, &at, 0, Ending::Newline)); } else { w.write_str(" "); } @@ -1189,14 +1189,15 @@ fn item_trait_alias( it: &clean::Item, t: &clean::TraitAlias, ) { + let at = AmbiguityTable::empty(); wrap_item(w, |w| { write!( w, "{attrs}trait {name}{generics}{where_b} = {bounds};", attrs = render_attributes_in_pre(it, "", cx), name = it.name.unwrap(), - generics = t.generics.print(cx), - where_b = print_where_clause(&t.generics, cx, 0, Ending::Newline), + generics = t.generics.print(cx, &at), + where_b = print_where_clause(&t.generics, cx, &at, 0, Ending::Newline), bounds = bounds(&t.bounds, true, cx), ) .unwrap(); @@ -1217,14 +1218,15 @@ fn item_opaque_ty( it: &clean::Item, t: &clean::OpaqueTy, ) { + let at = AmbiguityTable::empty(); wrap_item(w, |w| { write!( w, "{attrs}type {name}{generics}{where_clause} = impl {bounds};", attrs = render_attributes_in_pre(it, "", cx), name = it.name.unwrap(), - generics = t.generics.print(cx), - where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), + generics = t.generics.print(cx, &at), + where_clause = print_where_clause(&t.generics, cx, &at, 0, Ending::Newline), bounds = bounds(&t.bounds, false, cx), ) .unwrap(); @@ -1243,15 +1245,16 @@ fn item_opaque_ty( fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::TypeAlias) { fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) { wrap_item(w, |w| { + let at = AmbiguityTable::empty(); write!( w, "{attrs}{vis}type {name}{generics}{where_clause} = {type_};", attrs = render_attributes_in_pre(it, "", cx), vis = visibility_print_with_space(it, cx), name = it.name.unwrap(), - generics = t.generics.print(cx), - where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), - type_ = t.type_.print(cx), + generics = t.generics.print(cx, &at), + where_clause = print_where_clause(&t.generics, cx, &at, 0, Ending::Newline), + type_ = t.type_.print(cx, &at), ); }); } @@ -1273,8 +1276,8 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c let variants_len = variants.len(); let variants_count = variants_iter().count(); let has_stripped_entries = variants_len != variants_count; - - write!(w, "enum {}{}", it.name.unwrap(), t.generics.print(cx)); + let at = AmbiguityTable::empty(); + write!(w, "enum {}{}", it.name.unwrap(), t.generics.print(cx, &at)); render_enum_fields( w, cx, @@ -1290,10 +1293,11 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c } clean::TypeAliasInnerType::Union { fields } => { wrap_item(w, |w| { + let at = AmbiguityTable::empty(); let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); let has_stripped_fields = fields.len() != fields_count; - write!(w, "union {}{}", it.name.unwrap(), t.generics.print(cx)); + write!(w, "union {}{}", it.name.unwrap(), t.generics.print(cx, &at)); render_struct_fields( w, Some(&t.generics), @@ -1309,10 +1313,11 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c } clean::TypeAliasInnerType::Struct { ctor_kind, fields } => { wrap_item(w, |w| { + let at = AmbiguityTable::empty(); let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); let has_stripped_fields = fields.len() != fields_count; - write!(w, "struct {}{}", it.name.unwrap(), t.generics.print(cx)); + write!(w, "struct {}{}", it.name.unwrap(), t.generics.print(cx, &at)); render_struct_fields( w, Some(&t.generics), @@ -1475,8 +1480,9 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean: ty: &'a clean::Type, ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { display_fn(move |f| { + let at = AmbiguityTable::empty(); let cx = self.cx.borrow(); - let v = ty.print(*cx); + let v = ty.print(*cx, &at); write!(f, "{v}") }) } @@ -1517,7 +1523,10 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>( } match *ty.kind { clean::StrippedItem(box clean::StructFieldItem(_)) => f.write_str("_")?, - clean::StructFieldItem(ref ty) => write!(f, "{}", ty.print(cx))?, + clean::StructFieldItem(ref ty) => { + let at = AmbiguityTable::empty(); + write!(f, "{}", ty.print(cx, &at))?; + } _ => unreachable!(), } } @@ -1529,12 +1538,13 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: let count_variants = e.variants().count(); wrap_item(w, |w| { render_attributes_in_code(w, it, cx); + let at = AmbiguityTable::empty(); write!( w, "{}enum {}{}", visibility_print_with_space(it, cx), it.name.unwrap(), - e.generics.print(cx), + e.generics.print(cx, &at), ); render_enum_fields( @@ -1620,7 +1630,8 @@ fn render_enum_fields( enum_def_id: DefId, ) { let should_show_enum_discriminant = should_show_enum_discriminant(cx, enum_def_id, variants); - if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx)) { + let at = AmbiguityTable::empty(); + if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx, &at)) { // If there wasn't a `where` clause, we add a whitespace. w.write_str(" "); } @@ -1763,6 +1774,7 @@ fn item_variants( {}", document_non_exhaustive(variant) ); + let at = AmbiguityTable::empty(); for field in fields { match *field.kind { clean::StrippedItem(box clean::StructFieldItem(_)) => {} @@ -1780,7 +1792,7 @@ fn item_variants( {f}: {t}\ ", f = field.name.unwrap(), - t = ty.print(cx), + t = ty.print(cx, &at), ); write!( w, @@ -1859,15 +1871,15 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle wrap_item(w, |w| { let tcx = cx.tcx(); render_attributes_in_code(w, it, cx); - + let at = AmbiguityTable::empty(); write!( w, "{vis}const {name}{generics}: {typ}{where_clause}", vis = visibility_print_with_space(it, cx), name = it.name.unwrap(), - generics = c.generics.print(cx), - typ = c.type_.print(cx), - where_clause = print_where_clause(&c.generics, cx, 0, Ending::NoNewline), + generics = c.generics.print(cx, &at), + typ = c.type_.print(cx, &at), + where_clause = print_where_clause(&c.generics, cx, &at, 0, Ending::NoNewline), ); // FIXME: The code below now prints @@ -1942,6 +1954,7 @@ fn item_fields( document_non_exhaustive_header(it), ); write_section_heading(w, &title, "fields", Some("fields"), document_non_exhaustive(it)); + let at = AmbiguityTable::empty(); for (index, (field, ty)) in fields.enumerate() { let field_name = field.name.map_or_else(|| index.to_string(), |sym| sym.as_str().to_string()); @@ -1953,7 +1966,7 @@ fn item_fields( {field_name}: {ty}\ ", item_type = ItemType::StructField, - ty = ty.print(cx) + ty = ty.print(cx, &at) ); write!(w, "{}", document(cx, field, Some(it), HeadingOffset::H3)); } @@ -1964,13 +1977,14 @@ fn item_fields( fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { wrap_item(w, |buffer| { render_attributes_in_code(buffer, it, cx); + let at = AmbiguityTable::empty(); write!( buffer, "{vis}static {mutability}{name}: {typ}", vis = visibility_print_with_space(it, cx), mutability = s.mutability.print_with_space(), name = it.name.unwrap(), - typ = s.type_.print(cx) + typ = s.type_.print(cx, &at) ) .unwrap(); }); @@ -2053,6 +2067,7 @@ pub(super) fn item_path(ty: ItemType, name: &str) -> String { fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool, cx: &Context<'_>) -> String { let mut bounds = String::new(); + let at = AmbiguityTable::empty(); if !t_bounds.is_empty() { if !trait_alias { bounds.push_str(": "); @@ -2061,7 +2076,7 @@ fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool, cx: &Context<'_>) if i > 0 { bounds.push_str(" + "); } - bounds.push_str(&p.print(cx).to_string()); + bounds.push_str(&p.print(cx, &at).to_string()); } } bounds @@ -2082,7 +2097,8 @@ struct ImplString(String); impl ImplString { fn new(i: &Impl, cx: &Context<'_>) -> ImplString { - ImplString(format!("{}", i.inner_impl().print(false, cx))) + let at = AmbiguityTable::empty(); + ImplString(format!("{}", i.inner_impl().print(false, cx, &at))) } } @@ -2143,12 +2159,12 @@ fn render_union<'a, 'cx: 'a>( ) -> impl fmt::Display + 'a + Captures<'cx> { display_fn(move |mut f| { write!(f, "{}union {}", visibility_print_with_space(it, cx), it.name.unwrap(),)?; - + let at = AmbiguityTable::empty(); let where_displayed = g .map(|g| { let mut buf = Buffer::html(); - write!(buf, "{}", g.print(cx)); - let where_displayed = print_where_clause_and_check(&mut buf, g, cx); + write!(buf, "{}", g.print(cx, &at)); + let where_displayed = print_where_clause_and_check(&mut buf, g, cx, &at); write!(f, "{buf}", buf = buf.into_inner()).unwrap(); where_displayed }) @@ -2174,7 +2190,7 @@ fn render_union<'a, 'cx: 'a>( " {}{}: {},\n", visibility_print_with_space(field, cx), field.name.unwrap(), - ty.print(cx) + ty.print(cx, &at) )?; } } @@ -2208,7 +2224,8 @@ fn render_struct( it.name.unwrap() ); if let Some(g) = g { - write!(w, "{}", g.print(cx)) + let at = AmbiguityTable::empty(); + write!(w, "{}", g.print(cx, &at)); } render_struct_fields( w, @@ -2232,10 +2249,11 @@ fn render_struct_fields( has_stripped_entries: bool, cx: &Context<'_>, ) { + let at = AmbiguityTable::empty(); match ty { None => { let where_displayed = - g.map(|g| print_where_clause_and_check(w, g, cx)).unwrap_or(false); + g.map(|g| print_where_clause_and_check(w, g, cx, &at)).unwrap_or(false); // If there wasn't a `where` clause, we add a whitespace. if !where_displayed { @@ -2257,7 +2275,7 @@ fn render_struct_fields( "\n{tab} {vis}{name}: {ty},", vis = visibility_print_with_space(field, cx), name = field.name.unwrap(), - ty = ty.print(cx), + ty = ty.print(cx, &at), ); } } @@ -2291,7 +2309,12 @@ fn render_struct_fields( match *field.kind { clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"), clean::StructFieldItem(ref ty) => { - write!(w, "{}{}", visibility_print_with_space(field, cx), ty.print(cx),) + write!( + w, + "{}{}", + visibility_print_with_space(field, cx), + ty.print(cx, &at), + ) } _ => unreachable!(), } @@ -2299,7 +2322,7 @@ fn render_struct_fields( } w.write_str(")"); if let Some(g) = g { - write!(w, "{}", print_where_clause(g, cx, 0, Ending::NoNewline)); + write!(w, "{}", print_where_clause(g, cx, &at, 0, Ending::NoNewline)); } // We only want a ";" when we are displaying a tuple struct, not a variant tuple struct. if structhead { @@ -2309,7 +2332,7 @@ fn render_struct_fields( Some(CtorKind::Const) => { // Needed for PhantomData. if let Some(g) = g { - write!(w, "{}", print_where_clause(g, cx, 0, Ending::NoNewline)); + write!(w, "{}", print_where_clause(g, cx, &at, 0, Ending::NoNewline)); } w.write_str(";"); } diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 3d28937eb99e1..f45addfc37da0 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::{self, TyCtxt}; use crate::{ clean, formats::{item_type::ItemType, Impl}, - html::{format::Buffer, markdown::IdMap}, + html::{ambiguity::AmbiguityTable, format::Buffer, markdown::IdMap}, }; use super::{item_ty_to_section, Context, ItemSection}; @@ -423,10 +423,11 @@ fn sidebar_deref_methods<'a>( } else { Cow::Borrowed("deref-methods") }; + let at = AmbiguityTable::empty(); let title = format!( "Methods from {:#}", - impl_.inner_impl().trait_.as_ref().unwrap().print(cx), - real_target.print(cx), + impl_.inner_impl().trait_.as_ref().unwrap().print(cx, &at), + real_target.print(cx, &at), ); // We want links' order to be reproducible so we don't use unstable sort. ret.sort(); @@ -530,7 +531,8 @@ fn sidebar_render_assoc_items( ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "", ty::ImplPolarity::Negative => "!", }; - let generated = Link::new(encoded, format!("{prefix}{:#}", trait_.print(cx))); + let at = AmbiguityTable::empty(); + let generated = Link::new(encoded, format!("{prefix}{:#}", trait_.print(cx, &at))); if links.insert(generated.clone()) { Some(generated) } else { None } }) .collect::>>(); diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index fbd45b2b48ef9..82b0316735b4e 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -23,6 +23,7 @@ use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::formats::Impl; +use crate::html::ambiguity::AmbiguityTable; use crate::html::format::Buffer; use crate::html::render::{AssocItemLink, ImplRenderingParameters}; use crate::html::{layout, static_files}; @@ -534,11 +535,12 @@ else if (window.initSearch) window.initSearch(searchIndex); .values() .flat_map(|AliasedTypeImpl { impl_, type_aliases }| { let mut ret = Vec::new(); + let at = AmbiguityTable::empty(); let trait_ = impl_ .inner_impl() .trait_ .as_ref() - .map(|trait_| format!("{:#}", trait_.print(cx))); + .map(|trait_| format!("{:#}", trait_.print(cx, &at))); // render_impl will filter out "impossible-to-call" methods // to make that functionality work here, it needs to be called with // each type alias, and if it gives a different result, split the impl @@ -692,8 +694,10 @@ else if (window.initSearch) window.initSearch(searchIndex); if imp.impl_item.item_id.krate() == did.krate || !imp.impl_item.item_id.is_local() { None } else { + let at = AmbiguityTable::empty(); + let text = imp.inner_impl().print(false, cx, &at).to_string(); Some(Implementor { - text: imp.inner_impl().print(false, cx).to_string(), + text, synthetic: imp.inner_impl().kind.is_auto(), types: collect_paths_for_type(imp.inner_impl().for_.clone(), cache), }) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 18651875130fc..b270dc0f42a99 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -10,6 +10,7 @@ #![feature(iter_intersperse)] #![feature(lazy_cell)] #![feature(let_chains)] +#![feature(map_entry_replace)] #![feature(never_type)] #![feature(round_char_boundary)] #![feature(test)] diff --git a/tests/rustdoc/fn_param_ambiguities.rs b/tests/rustdoc/fn_param_ambiguities.rs index 6e9f37de0ee96..ba35b6471cc12 100644 --- a/tests/rustdoc/fn_param_ambiguities.rs +++ b/tests/rustdoc/fn_param_ambiguities.rs @@ -9,5 +9,5 @@ pub mod Y { pub enum B {} } -// @has fn_param_ambiguities/fn.f.html //pre 'pub fn f(xa: fn_param_ambiguities::X::A, ya: fn_param_ambiguities::Y::A, yb: B, xc: C)' +// @has fn_param_ambiguities/fn.f.html //pre 'pub fn f(xa: X::A, ya: Y::A, yb: B, xc: C)' pub fn f(xa: X::A, ya: Y::A, yb : Y::B, xc: X::C) {}