From 56fe372cedb3329ee652eb4da761142a314482f4 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 11 Apr 2021 01:08:31 +0800 Subject: [PATCH 1/5] Do not ignore path segments in the middle in `#[allow]`/`#[warn]`/`#[deny]`/`#[forbid]` attributes --- compiler/rustc_lint/src/levels.rs | 81 ++++++++++++++--------------- src/test/ui/lint/issue-83477.rs | 16 ++++++ src/test/ui/lint/issue-83477.stderr | 30 +++++++++++ 3 files changed, 84 insertions(+), 43 deletions(-) create mode 100644 src/test/ui/lint/issue-83477.rs create mode 100644 src/test/ui/lint/issue-83477.stderr diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index e0857ad1eb997..54909381a10a5 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -236,10 +236,9 @@ impl<'s> LintLevelsBuilder<'s> { Some(lvl) => lvl, }; - let meta = unwrap_or!(attr.meta(), continue); self.sess.mark_attr_used(attr); - let mut metas = unwrap_or!(meta.meta_item_list(), continue); + let mut metas = unwrap_or!(attr.meta_item_list(), continue); if metas.is_empty() { // FIXME (#55112): issue unused-attributes lint for `#[level()]` @@ -255,8 +254,6 @@ impl<'s> LintLevelsBuilder<'s> { ast::MetaItemKind::Word => {} // actual lint names handled later ast::MetaItemKind::NameValue(ref name_value) => { if item.path == sym::reason { - // found reason, reslice meta list to exclude it - metas = &metas[0..metas.len() - 1]; // FIXME (#55112): issue unused-attributes lint if we thereby // don't have any lint names (`#[level(reason = "foo")]`) if let ast::LitKind::Str(rationale, _) = name_value.kind { @@ -275,6 +272,8 @@ impl<'s> LintLevelsBuilder<'s> { .span_label(name_value.span, "reason must be a string literal") .emit(); } + // found reason, reslice meta list to exclude it + metas.pop().unwrap(); } else { bad_attr(item.span) .span_label(item.span, "bad attribute argument") @@ -288,10 +287,10 @@ impl<'s> LintLevelsBuilder<'s> { } for li in metas { - let meta_item = match li.meta_item() { - Some(meta_item) if meta_item.is_word() => meta_item, + let sp = li.span(); + let mut meta_item = match li { + ast::NestedMetaItem::MetaItem(meta_item) if meta_item.is_word() => meta_item, _ => { - let sp = li.span(); let mut err = bad_attr(sp); let mut add_label = true; if let Some(item) = li.meta_item() { @@ -330,15 +329,19 @@ impl<'s> LintLevelsBuilder<'s> { continue; } - Some(tool_ident.name) + Some(meta_item.path.segments.remove(0).ident.name) } else { None }; - let name = meta_item.path.segments.last().expect("empty lint name").ident.name; - let lint_result = store.check_lint_name(&name.as_str(), tool_name); + let name = pprust::path_to_string(&meta_item.path); + let lint_result = store.check_lint_name(&name, tool_name); match &lint_result { CheckLintNameResult::Ok(ids) => { - let src = LintLevelSource::Node(name, li.span(), reason); + let src = LintLevelSource::Node( + meta_item.path.segments.last().expect("empty lint name").ident.name, + sp, + reason, + ); for &id in *ids { self.check_gated_lint(id, attr.span); self.insert_spec(&mut specs, id, (level, src)); @@ -351,7 +354,7 @@ impl<'s> LintLevelsBuilder<'s> { let complete_name = &format!("{}::{}", tool_name.unwrap(), name); let src = LintLevelSource::Node( Symbol::intern(complete_name), - li.span(), + sp, reason, ); for id in ids { @@ -367,7 +370,7 @@ impl<'s> LintLevelsBuilder<'s> { lint, lvl, src, - Some(li.span().into()), + Some(sp.into()), |lint| { let msg = format!( "lint name `{}` is deprecated \ @@ -376,7 +379,7 @@ impl<'s> LintLevelsBuilder<'s> { ); lint.build(&msg) .span_suggestion( - li.span(), + sp, "change it to", new_lint_name.to_string(), Applicability::MachineApplicable, @@ -387,7 +390,7 @@ impl<'s> LintLevelsBuilder<'s> { let src = LintLevelSource::Node( Symbol::intern(&new_lint_name), - li.span(), + sp, reason, ); for id in ids { @@ -414,12 +417,12 @@ impl<'s> LintLevelsBuilder<'s> { lint, renamed_lint_level, src, - Some(li.span().into()), + Some(sp.into()), |lint| { let mut err = lint.build(&msg); if let Some(new_name) = &renamed { err.span_suggestion( - li.span(), + sp, "use the new name", new_name.to_string(), Applicability::MachineApplicable, @@ -433,30 +436,23 @@ impl<'s> LintLevelsBuilder<'s> { let lint = builtin::UNKNOWN_LINTS; let (level, src) = self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess); - struct_lint_level( - self.sess, - lint, - level, - src, - Some(li.span().into()), - |lint| { - let name = if let Some(tool_name) = tool_name { - format!("{}::{}", tool_name, name) - } else { - name.to_string() - }; - let mut db = lint.build(&format!("unknown lint: `{}`", name)); - if let Some(suggestion) = suggestion { - db.span_suggestion( - li.span(), - "did you mean", - suggestion.to_string(), - Applicability::MachineApplicable, - ); - } - db.emit(); - }, - ); + struct_lint_level(self.sess, lint, level, src, Some(sp.into()), |lint| { + let name = if let Some(tool_name) = tool_name { + format!("{}::{}", tool_name, name) + } else { + name.to_string() + }; + let mut db = lint.build(&format!("unknown lint: `{}`", name)); + if let Some(suggestion) = suggestion { + db.span_suggestion( + sp, + "did you mean", + suggestion.to_string(), + Applicability::MachineApplicable, + ); + } + db.emit(); + }); } } // If this lint was renamed, apply the new lint instead of ignoring the attribute. @@ -466,8 +462,7 @@ impl<'s> LintLevelsBuilder<'s> { // Ignore any errors or warnings that happen because the new name is inaccurate // NOTE: `new_name` already includes the tool name, so we don't have to add it again. if let CheckLintNameResult::Ok(ids) = store.check_lint_name(&new_name, None) { - let src = - LintLevelSource::Node(Symbol::intern(&new_name), li.span(), reason); + let src = LintLevelSource::Node(Symbol::intern(&new_name), sp, reason); for &id in ids { self.check_gated_lint(id, attr.span); self.insert_spec(&mut specs, id, (level, src)); diff --git a/src/test/ui/lint/issue-83477.rs b/src/test/ui/lint/issue-83477.rs new file mode 100644 index 0000000000000..0eba52acfa3d8 --- /dev/null +++ b/src/test/ui/lint/issue-83477.rs @@ -0,0 +1,16 @@ +// check-pass +#![warn(rustc::internal)] + +#[allow(rustc::foo::bar::default_hash_types)] +//~^ WARN unknown lint: `rustc::foo::bar::default_hash_types` +//~| HELP did you mean +//~| SUGGESTION rustc::default_hash_types +#[allow(rustc::foo::default_hash_types)] +//~^ WARN unknown lint: `rustc::foo::default_hash_types` +//~| HELP did you mean +//~| SUGGESTION rustc::default_hash_types +fn main() { + let _ = std::collections::HashMap::::new(); + //~^ WARN Prefer FxHashMap over HashMap, it has better performance + //~| HELP use +} diff --git a/src/test/ui/lint/issue-83477.stderr b/src/test/ui/lint/issue-83477.stderr new file mode 100644 index 0000000000000..dbe0c9e01301f --- /dev/null +++ b/src/test/ui/lint/issue-83477.stderr @@ -0,0 +1,30 @@ +warning: unknown lint: `rustc::foo::bar::default_hash_types` + --> $DIR/issue-83477.rs:4:9 + | +LL | #[allow(rustc::foo::bar::default_hash_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `rustc::default_hash_types` + | + = note: `#[warn(unknown_lints)]` on by default + +warning: unknown lint: `rustc::foo::default_hash_types` + --> $DIR/issue-83477.rs:8:9 + | +LL | #[allow(rustc::foo::default_hash_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `rustc::default_hash_types` + +warning: Prefer FxHashMap over HashMap, it has better performance + --> $DIR/issue-83477.rs:13:31 + | +LL | let _ = std::collections::HashMap::::new(); + | ^^^^^^^ help: use: `FxHashMap` + | +note: the lint level is defined here + --> $DIR/issue-83477.rs:2:9 + | +LL | #![warn(rustc::internal)] + | ^^^^^^^^^^^^^^^ + = note: `#[warn(rustc::default_hash_types)]` implied by `#[warn(rustc::internal)]` + = note: a `use rustc_data_structures::fx::FxHashMap` may be necessary + +warning: 3 warnings emitted + From 2dfd0bfe1087fef83f26b52b32c8b54fb621b6b9 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 10 Apr 2021 14:22:06 -0700 Subject: [PATCH 2/5] rustdoc: clean up and test macro visibility print This fixes the overly-complex invariant mentioned in , where the macro source can't have any links in it only because the cache hasn't been populated yet. --- src/librustdoc/clean/mod.rs | 4 +-- src/librustdoc/html/format.rs | 48 +++++++++++++++++++++++++++------- src/test/rustdoc/decl_macro.rs | 17 ++++++++++++ 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 217e899001ef9..7d33cf210139c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2287,14 +2287,14 @@ impl Clean for (&hir::MacroDef<'_>, Option) { if matchers.len() <= 1 { format!( "{}macro {}{} {{\n ...\n}}", - vis.print_with_space(cx.tcx, def_id, &cx.cache), + vis.to_src_with_space(cx.tcx, def_id), name, matchers.iter().map(|span| span.to_src(cx)).collect::(), ) } else { format!( "{}macro {} {{\n{}}}", - vis.print_with_space(cx.tcx, def_id, &cx.cache), + vis.to_src_with_space(cx.tcx, def_id), name, matchers .iter() diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index a004ee5054ed6..41f531e77e5b5 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1186,8 +1186,6 @@ impl clean::Visibility { item_did: DefId, cache: &'a Cache, ) -> impl fmt::Display + 'a + Captures<'tcx> { - use rustc_span::symbol::kw; - let to_print = match self { clean::Public => "pub ".to_owned(), clean::Inherited => String::new(), @@ -1212,18 +1210,11 @@ impl clean::Visibility { } else { let path = tcx.def_path(vis_did); debug!("path={:?}", path); - let first_name = - path.data[0].data.get_opt_name().expect("modules are always named"); // modified from `resolved_path()` to work with `DefPathData` let last_name = path.data.last().unwrap().data.get_opt_name().unwrap(); let anchor = anchor(vis_did, &last_name.as_str(), cache).to_string(); - let mut s = "pub(".to_owned(); - if path.data.len() != 1 - || (first_name != kw::SelfLower && first_name != kw::Super) - { - s.push_str("in "); - } + let mut s = "pub(in ".to_owned(); for seg in &path.data[..path.data.len() - 1] { s.push_str(&format!("{}::", seg.data.get_opt_name().unwrap())); } @@ -1234,6 +1225,43 @@ impl clean::Visibility { }; display_fn(move |f| f.write_str(&to_print)) } + + /// 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. + crate fn to_src_with_space<'a, 'tcx: 'a>( + self, + tcx: TyCtxt<'tcx>, + item_did: DefId, + ) -> impl fmt::Display + 'a + Captures<'tcx> { + let to_print = match self { + clean::Public => "pub ".to_owned(), + clean::Inherited => String::new(), + clean::Visibility::Restricted(vis_did) => { + // FIXME(camelid): This may not work correctly if `item_did` is a module. + // However, rustdoc currently never displays a module's + // visibility, so it shouldn't matter. + let parent_module = find_nearest_parent_module(tcx, item_did); + + if vis_did.index == CRATE_DEF_INDEX { + "pub(crate) ".to_owned() + } else if parent_module == Some(vis_did) { + // `pub(in foo)` where `foo` is the parent module + // is the same as no visibility modifier + String::new() + } else if parent_module + .map(|parent| find_nearest_parent_module(tcx, parent)) + .flatten() + == Some(vis_did) + { + "pub(super) ".to_owned() + } else { + format!("pub(in {}) ", tcx.def_path_str(vis_did)) + } + } + }; + display_fn(move |f| f.write_str(&to_print)) + } } crate trait PrintWithSpace { diff --git a/src/test/rustdoc/decl_macro.rs b/src/test/rustdoc/decl_macro.rs index e48a56f906c95..ede3f455a2044 100644 --- a/src/test/rustdoc/decl_macro.rs +++ b/src/test/rustdoc/decl_macro.rs @@ -1,3 +1,5 @@ +// compile-flags: --document-private-items + #![feature(decl_macro)] // @has decl_macro/macro.my_macro.html //pre 'pub macro my_macro() {' @@ -37,3 +39,18 @@ pub macro my_macro_multi { pub macro by_example_single { ($foo:expr) => {} } + +mod a { + mod b { + // @has decl_macro/a/b/macro.by_example_vis.html //pre 'pub(super) macro by_example_vis($foo:expr) {' + pub(in super) macro by_example_vis { + ($foo:expr) => {} + } + mod c { + // @has decl_macro/a/b/c/macro.by_example_vis_named.html //pre 'pub(in a) macro by_example_vis_named($foo:expr) {' + pub(in a) macro by_example_vis_named { + ($foo:expr) => {} + } + } + } +} From 9ecfae44d74cadd58c9909da8f4a2410dd583c03 Mon Sep 17 00:00:00 2001 From: Soveu Date: Fri, 16 Apr 2021 16:29:11 +0200 Subject: [PATCH 3/5] builtin derive macros: fix error with const generics default --- .../src/deriving/generic/mod.rs | 15 +++++++++++++-- src/test/ui/derives/derive-macro-const-default.rs | 14 ++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/derives/derive-macro-const-default.rs diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 04753926c3e2a..a3decff3ae7e1 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -541,7 +541,7 @@ impl<'a> TraitDef<'a> { self.generics.to_generics(cx, self.span, type_ident, generics); // Create the generic parameters - params.extend(generics.params.iter().map(|param| match param.kind { + params.extend(generics.params.iter().map(|param| match ¶m.kind { GenericParamKind::Lifetime { .. } => param.clone(), GenericParamKind::Type { .. } => { // I don't think this can be moved out of the loop, since @@ -561,7 +561,18 @@ impl<'a> TraitDef<'a> { cx.typaram(self.span, param.ident, vec![], bounds, None) } - GenericParamKind::Const { .. } => param.clone(), + GenericParamKind::Const { ty, kw_span, .. } => { + let const_nodefault_kind = GenericParamKind::Const { + ty: ty.clone(), + kw_span: kw_span.clone(), + + // We can't have default values inside impl block + default: None, + }; + let mut param_clone = param.clone(); + param_clone.kind = const_nodefault_kind; + param_clone + } })); // and similarly for where clauses diff --git a/src/test/ui/derives/derive-macro-const-default.rs b/src/test/ui/derives/derive-macro-const-default.rs new file mode 100644 index 0000000000000..a844f2d20237b --- /dev/null +++ b/src/test/ui/derives/derive-macro-const-default.rs @@ -0,0 +1,14 @@ +// check-pass +#![allow(incomplete_features)] +#![feature(const_generics_defaults)] + +#[derive(Clone, PartialEq, Debug)] +struct Example([T; N]); + +fn main() { + let a = Example([(); 16]); + let b = a.clone(); + if a != b { + let _c = format!("{:?}", a); + } +} From af90cac0e15de4479c8880f6ab80194a8d2b7291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=C3=A9nore=20Bouttefeux?= Date: Fri, 16 Apr 2021 17:04:15 +0200 Subject: [PATCH 4/5] fix reporting return type in some cases --- compiler/rustc_typeck/src/check/coercion.rs | 22 ---------------- compiler/rustc_typeck/src/check/demand.rs | 29 +++++++++++++++++++++ src/test/ui/closures/issue-84128.rs | 16 ++++++++++++ src/test/ui/closures/issue-84128.stderr | 15 +++++++++++ 4 files changed, 60 insertions(+), 22 deletions(-) create mode 100644 src/test/ui/closures/issue-84128.rs create mode 100644 src/test/ui/closures/issue-84128.stderr diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 37538267b866a..fd7c50e978800 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -1492,28 +1492,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) { self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output); } - - if let Some(sp) = fcx.ret_coercion_span.get() { - // If the closure has an explicit return type annotation, - // then a type error may occur at the first return expression we - // see in the closure (if it conflicts with the declared - // return type). Skip adding a note in this case, since it - // would be incorrect. - if !err.span.primary_spans().iter().any(|&span| span == sp) { - let hir = fcx.tcx.hir(); - let body_owner = hir.body_owned_by(hir.enclosing_body_owner(fcx.body_id)); - if fcx.tcx.is_closure(hir.body_owner_def_id(body_owner).to_def_id()) { - err.span_note( - sp, - &format!( - "return type inferred to be `{}` here", - fcx.resolve_vars_if_possible(expected) - ), - ); - } - } - } - err } diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index d879b6e97dcfb..e5fcdcfa74315 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -37,6 +37,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_missing_parentheses(err, expr); self.note_need_for_fn_pointer(err, expected, expr_ty); self.note_internal_mutation_in_method(err, expr, expected, expr_ty); + self.report_closure_infered_return_type(err, expected) } // Requires that the two types unify, and prints an error message if @@ -1061,4 +1062,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => false, } } + + // Report the type inferred by the return statement. + fn report_closure_infered_return_type( + &self, + err: &mut DiagnosticBuilder<'_>, + expected: Ty<'tcx>, + ) { + if let Some(sp) = self.ret_coercion_span.get() { + // If the closure has an explicit return type annotation, + // then a type error may occur at the first return expression we + // see in the closure (if it conflicts with the declared + // return type). Skip adding a note in this case, since it + // would be incorrect. + if !err.span.primary_spans().iter().any(|&span| span == sp) { + let hir = self.tcx.hir(); + let body_owner = hir.body_owned_by(hir.enclosing_body_owner(self.body_id)); + if self.tcx.is_closure(hir.body_owner_def_id(body_owner).to_def_id()) { + err.span_note( + sp, + &format!( + "return type inferred to be `{}` here", + self.resolve_vars_if_possible(expected) + ), + ); + } + } + } + } } diff --git a/src/test/ui/closures/issue-84128.rs b/src/test/ui/closures/issue-84128.rs new file mode 100644 index 0000000000000..f81d7cfaa654b --- /dev/null +++ b/src/test/ui/closures/issue-84128.rs @@ -0,0 +1,16 @@ +// test for issue 84128 +// missing suggestion for similar ADT type with diffetent generic paramenter +// on closure ReturnNoExpression + +struct Foo(T); + +fn main() { + || { + if false { + return Foo(0); + } + + Foo(()) + //~^ ERROR mismatched types [E0308] + }; +} diff --git a/src/test/ui/closures/issue-84128.stderr b/src/test/ui/closures/issue-84128.stderr new file mode 100644 index 0000000000000..70d9273ddf7ce --- /dev/null +++ b/src/test/ui/closures/issue-84128.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/issue-84128.rs:13:13 + | +LL | Foo(()) + | ^^ expected integer, found `()` + | +note: return type inferred to be `{integer}` here + --> $DIR/issue-84128.rs:10:20 + | +LL | return Foo(0); + | ^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From 6109cee35cd2a496fb91c47688470cbed8979e99 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 16 Apr 2021 08:46:47 -0700 Subject: [PATCH 5/5] rustdoc: get rid of unused path printing code The code for printing a raw path is only used in utils.rs, which only prints the alternative (non-HTML) format. Path has a function that does the same thing without HTML support, so use that instead. --- src/librustdoc/clean/utils.rs | 2 +- src/librustdoc/html/format.rs | 42 ----------------------------------- 2 files changed, 1 insertion(+), 43 deletions(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 1e79bd0912884..c2a971d637513 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -401,7 +401,7 @@ crate fn resolve_type(cx: &mut DocContext<'_>, path: Path, id: hir::HirId) -> Ty return Generic(kw::SelfUpper); } Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => { - return Generic(Symbol::intern(&format!("{:#}", path.print(&cx.cache, cx.tcx)))); + return Generic(Symbol::intern(&path.whole_name())); } Res::SelfTy(..) | Res::Def(DefKind::TyParam | DefKind::AssocTy, _) => true, _ => false, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index a004ee5054ed6..4a091ee911425 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -453,48 +453,6 @@ impl clean::GenericArgs { } } -impl clean::PathSegment { - crate fn print<'a, 'tcx: 'a>( - &'a self, - cache: &'a Cache, - tcx: TyCtxt<'tcx>, - ) -> impl fmt::Display + 'a + Captures<'tcx> { - display_fn(move |f| { - if f.alternate() { - write!(f, "{}{:#}", self.name, self.args.print(cache, tcx)) - } else { - write!(f, "{}{}", self.name, self.args.print(cache, tcx)) - } - }) - } -} - -impl clean::Path { - crate fn print<'a, 'tcx: 'a>( - &'a self, - cache: &'a Cache, - tcx: TyCtxt<'tcx>, - ) -> impl fmt::Display + 'a + Captures<'tcx> { - display_fn(move |f| { - if self.global { - f.write_str("::")? - } - - for (i, seg) in self.segments.iter().enumerate() { - if i > 0 { - f.write_str("::")? - } - if f.alternate() { - write!(f, "{:#}", seg.print(cache, tcx))?; - } else { - write!(f, "{}", seg.print(cache, tcx))?; - } - } - Ok(()) - }) - } -} - crate fn href(did: DefId, cache: &Cache) -> Option<(String, ItemType, Vec)> { if !did.is_local() && !cache.access_levels.is_public(did) && !cache.document_private { return None;