1 use crate::clean
::auto_trait
::AutoTraitFinder
;
2 use crate::clean
::blanket_impl
::BlanketImplFinder
;
4 inline
, Clean
, Crate
, Deprecation
, ExternalCrate
, FnDecl
, FnRetTy
, Generic
, GenericArg
,
5 GenericArgs
, GenericBound
, Generics
, GetDefId
, ImportSource
, Item
, ItemEnum
, MacroKind
, Path
,
6 PathSegment
, Primitive
, PrimitiveType
, ResolvedPath
, Span
, Stability
, Type
, TypeBinding
,
7 TypeKind
, Visibility
, WherePredicate
,
9 use crate::core
::DocContext
;
11 use itertools
::Itertools
;
12 use rustc_data_structures
::fx
::FxHashSet
;
14 use rustc_hir
::def
::{DefKind, Res}
;
15 use rustc_hir
::def_id
::{DefId, LOCAL_CRATE}
;
16 use rustc_middle
::mir
::interpret
::{sign_extend, ConstValue, Scalar}
;
17 use rustc_middle
::ty
::subst
::{GenericArgKind, SubstsRef}
;
18 use rustc_middle
::ty
::{self, DefIdTree, Ty}
;
19 use rustc_span
::symbol
::{kw, sym, Symbol}
;
22 pub fn krate(mut cx
: &mut DocContext
<'_
>) -> Crate
{
23 use crate::visit_lib
::LibEmbargoVisitor
;
25 let krate
= cx
.tcx
.hir().krate();
26 let module
= crate::visit_ast
::RustdocVisitor
::new(&mut cx
).visit(krate
);
28 let mut r
= cx
.renderinfo
.get_mut();
29 r
.deref_trait_did
= cx
.tcx
.lang_items().deref_trait();
30 r
.deref_mut_trait_did
= cx
.tcx
.lang_items().deref_mut_trait();
31 r
.owned_box_did
= cx
.tcx
.lang_items().owned_box();
33 let mut externs
= Vec
::new();
34 for &cnum
in cx
.tcx
.crates().iter() {
35 externs
.push((cnum
, cnum
.clean(cx
)));
36 // Analyze doc-reachability for extern items
37 LibEmbargoVisitor
::new(&mut cx
).visit_lib(cnum
);
39 externs
.sort_by(|&(a
, _
), &(b
, _
)| a
.cmp(&b
));
41 // Clean the crate, translating the entire librustc_ast AST to one that is
42 // understood by rustdoc.
43 let mut module
= module
.clean(cx
);
44 let mut masked_crates
= FxHashSet
::default();
47 ItemEnum
::ModuleItem(ref module
) => {
48 for it
in &module
.items
{
49 // `compiler_builtins` should be masked too, but we can't apply
50 // `#[doc(masked)]` to the injected `extern crate` because it's unstable.
51 if it
.is_extern_crate()
52 && (it
.attrs
.has_doc_flag(sym
::masked
)
53 || cx
.tcx
.is_compiler_builtins(it
.def_id
.krate
))
55 masked_crates
.insert(it
.def_id
.krate
);
62 let ExternalCrate { name, src, primitives, keywords, .. }
= LOCAL_CRATE
.clean(cx
);
64 let m
= match module
.inner
{
65 ItemEnum
::ModuleItem(ref mut m
) => m
,
68 m
.items
.extend(primitives
.iter().map(|&(def_id
, prim
, ref attrs
)| Item
{
69 source
: Span
::empty(),
70 name
: Some(prim
.to_url_str().to_string()),
72 visibility
: Visibility
::Public
,
73 stability
: get_stability(cx
, def_id
),
74 deprecation
: get_deprecation(cx
, def_id
),
76 inner
: ItemEnum
::PrimitiveItem(prim
),
78 m
.items
.extend(keywords
.into_iter().map(|(def_id
, kw
, attrs
)| Item
{
79 source
: Span
::empty(),
80 name
: Some(kw
.clone()),
82 visibility
: Visibility
::Public
,
83 stability
: get_stability(cx
, def_id
),
84 deprecation
: get_deprecation(cx
, def_id
),
86 inner
: ItemEnum
::KeywordItem(kw
),
97 external_traits
: cx
.external_traits
.clone(),
103 // extract the stability index for a node from tcx, if possible
104 pub fn get_stability(cx
: &DocContext
<'_
>, def_id
: DefId
) -> Option
<Stability
> {
105 cx
.tcx
.lookup_stability(def_id
).clean(cx
)
108 pub fn get_deprecation(cx
: &DocContext
<'_
>, def_id
: DefId
) -> Option
<Deprecation
> {
109 cx
.tcx
.lookup_deprecation(def_id
).clean(cx
)
112 pub fn external_generic_args(
114 trait_did
: Option
<DefId
>,
116 bindings
: Vec
<TypeBinding
>,
117 substs
: SubstsRef
<'_
>,
119 let mut skip_self
= has_self
;
120 let mut ty_kind
= None
;
121 let args
: Vec
<_
> = substs
123 .filter_map(|kind
| match kind
.unpack() {
124 GenericArgKind
::Lifetime(lt
) => lt
.clean(cx
).map(GenericArg
::Lifetime
),
125 GenericArgKind
::Type(_
) if skip_self
=> {
129 GenericArgKind
::Type(ty
) => {
130 ty_kind
= Some(&ty
.kind
);
131 Some(GenericArg
::Type(ty
.clean(cx
)))
133 GenericArgKind
::Const(ct
) => Some(GenericArg
::Const(ct
.clean(cx
))),
138 // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
139 Some(did
) if cx
.tcx
.fn_trait_kind_from_lang_item(did
).is_some() => {
140 assert
!(ty_kind
.is_some());
141 let inputs
= match ty_kind
{
142 Some(ty
::Tuple(ref tys
)) => tys
.iter().map(|t
| t
.expect_ty().clean(cx
)).collect(),
143 _
=> return GenericArgs
::AngleBracketed { args, bindings }
,
146 // FIXME(#20299) return type comes from a projection now
147 // match types[1].kind {
148 // ty::Tuple(ref v) if v.is_empty() => None, // -> ()
149 // _ => Some(types[1].clean(cx))
151 GenericArgs
::Parenthesized { inputs, output }
153 _
=> GenericArgs
::AngleBracketed { args, bindings }
,
157 // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
158 // from Fn<(A, B,), C> to Fn(A, B) -> C
159 pub fn external_path(
162 trait_did
: Option
<DefId
>,
164 bindings
: Vec
<TypeBinding
>,
165 substs
: SubstsRef
<'_
>,
170 segments
: vec
![PathSegment
{
171 name
: name
.to_string(),
172 args
: external_generic_args(cx
, trait_did
, has_self
, bindings
, substs
),
177 /// The point of this function is to replace bounds with types.
179 /// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return
180 /// `[Display, Option]` (we just returns the list of the types, we don't care about the
181 /// wrapped types in here).
182 pub fn get_real_types(
187 ) -> FxHashSet
<(Type
, TypeKind
)> {
188 let arg_s
= arg
.print().to_string();
189 let mut res
= FxHashSet
::default();
191 // FIXME: remove this whole recurse thing when the recursion bug is fixed
194 if arg
.is_full_generic() {
195 if let Some(where_pred
) = generics
.where_predicates
.iter().find(|g
| match g
{
196 &WherePredicate
::BoundPredicate { ref ty, .. }
=> ty
.def_id() == arg
.def_id(),
199 let bounds
= where_pred
.get_bounds().unwrap_or_else(|| &[]);
200 for bound
in bounds
.iter() {
201 if let GenericBound
::TraitBound(ref poly_trait
, _
) = *bound
{
202 for x
in poly_trait
.generic_params
.iter() {
206 if let Some(ty
) = x
.get_type() {
207 let adds
= get_real_types(generics
, &ty
, cx
, recurse
+ 1);
208 if !adds
.is_empty() {
210 } else if !ty
.is_full_generic() {
212 ty
.def_id().and_then(|did
| cx
.tcx
.def_kind(did
).clean(cx
))
214 res
.insert((ty
, kind
));
222 if let Some(bound
) = generics
.params
.iter().find(|g
| g
.is_type() && g
.name
== arg_s
) {
223 for bound
in bound
.get_bounds().unwrap_or_else(|| &[]) {
224 if let Some(ty
) = bound
.get_trait_type() {
225 let adds
= get_real_types(generics
, &ty
, cx
, recurse
+ 1);
226 if !adds
.is_empty() {
228 } else if !ty
.is_full_generic() {
230 ty
.def_id().and_then(|did
| cx
.tcx
.def_kind(did
).clean(cx
))
232 res
.insert((ty
.clone(), kind
));
239 if let Some(kind
) = arg
.def_id().and_then(|did
| cx
.tcx
.def_kind(did
).clean(cx
)) {
240 res
.insert((arg
.clone(), kind
));
242 if let Some(gens
) = arg
.generics() {
243 for gen
in gens
.iter() {
244 if gen
.is_full_generic() {
245 let adds
= get_real_types(generics
, gen
, cx
, recurse
+ 1);
246 if !adds
.is_empty() {
249 } else if let Some(kind
) =
250 gen
.def_id().and_then(|did
| cx
.tcx
.def_kind(did
).clean(cx
))
252 res
.insert((gen
.clone(), kind
));
260 /// Return the full list of types when bounds have been resolved.
262 /// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return
263 /// `[u32, Display, Option]`.
264 pub fn get_all_types(
268 ) -> (Vec
<(Type
, TypeKind
)>, Vec
<(Type
, TypeKind
)>) {
269 let mut all_types
= FxHashSet
::default();
270 for arg
in decl
.inputs
.values
.iter() {
271 if arg
.type_
.is_self_type() {
274 let args
= get_real_types(generics
, &arg
.type_
, cx
, 0);
275 if !args
.is_empty() {
276 all_types
.extend(args
);
278 if let Some(kind
) = arg
.type_
.def_id().and_then(|did
| cx
.tcx
.def_kind(did
).clean(cx
)) {
279 all_types
.insert((arg
.type_
.clone(), kind
));
284 let ret_types
= match decl
.output
{
285 FnRetTy
::Return(ref return_type
) => {
286 let mut ret
= get_real_types(generics
, &return_type
, cx
, 0);
289 return_type
.def_id().and_then(|did
| cx
.tcx
.def_kind(did
).clean(cx
))
291 ret
.insert((return_type
.clone(), kind
));
294 ret
.into_iter().collect()
298 (all_types
.into_iter().collect(), ret_types
)
301 pub fn strip_type(ty
: Type
) -> Type
{
303 Type
::ResolvedPath { path, param_names, did, is_generic }
=> {
304 Type
::ResolvedPath { path: strip_path(&path), param_names, did, is_generic }
306 Type
::Tuple(inner_tys
) => {
307 Type
::Tuple(inner_tys
.iter().map(|t
| strip_type(t
.clone())).collect())
309 Type
::Slice(inner_ty
) => Type
::Slice(Box
::new(strip_type(*inner_ty
))),
310 Type
::Array(inner_ty
, s
) => Type
::Array(Box
::new(strip_type(*inner_ty
)), s
),
311 Type
::RawPointer(m
, inner_ty
) => Type
::RawPointer(m
, Box
::new(strip_type(*inner_ty
))),
312 Type
::BorrowedRef { lifetime, mutability, type_ }
=> {
313 Type
::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) }
315 Type
::QPath { name, self_type, trait_ }
=> Type
::QPath
{
317 self_type
: Box
::new(strip_type(*self_type
)),
318 trait_
: Box
::new(strip_type(*trait_
)),
324 pub fn strip_path(path
: &Path
) -> Path
{
328 .map(|s
| PathSegment
{
329 name
: s
.name
.clone(),
330 args
: GenericArgs
::AngleBracketed { args: vec![], bindings: vec![] }
,
334 Path { global: path.global, res: path.res, segments }
337 pub fn qpath_to_string(p
: &hir
::QPath
) -> String
{
338 let segments
= match *p
{
339 hir
::QPath
::Resolved(_
, ref path
) => &path
.segments
,
340 hir
::QPath
::TypeRelative(_
, ref segment
) => return segment
.ident
.to_string(),
343 let mut s
= String
::new();
344 for (i
, seg
) in segments
.iter().enumerate() {
348 if seg
.ident
.name
!= kw
::PathRoot
{
349 s
.push_str(&seg
.ident
.as_str());
355 pub fn build_deref_target_impls(cx
: &DocContext
<'_
>, items
: &[Item
], ret
: &mut Vec
<Item
>) {
356 use self::PrimitiveType
::*;
360 let target
= match item
.inner
{
361 ItemEnum
::TypedefItem(ref t
, true) => &t
.type_
,
364 let primitive
= match *target
{
365 ResolvedPath { did, .. }
if did
.is_local() => continue,
366 ResolvedPath { did, .. }
=> {
367 ret
.extend(inline
::build_impls(cx
, did
, None
));
370 _
=> match target
.primitive_type() {
375 let did
= match primitive
{
376 Isize
=> tcx
.lang_items().isize_impl(),
377 I8
=> tcx
.lang_items().i8_impl(),
378 I16
=> tcx
.lang_items().i16_impl(),
379 I32
=> tcx
.lang_items().i32_impl(),
380 I64
=> tcx
.lang_items().i64_impl(),
381 I128
=> tcx
.lang_items().i128_impl(),
382 Usize
=> tcx
.lang_items().usize_impl(),
383 U8
=> tcx
.lang_items().u8_impl(),
384 U16
=> tcx
.lang_items().u16_impl(),
385 U32
=> tcx
.lang_items().u32_impl(),
386 U64
=> tcx
.lang_items().u64_impl(),
387 U128
=> tcx
.lang_items().u128_impl(),
388 F32
=> tcx
.lang_items().f32_impl(),
389 F64
=> tcx
.lang_items().f64_impl(),
390 Char
=> tcx
.lang_items().char_impl(),
391 Bool
=> tcx
.lang_items().bool_impl(),
392 Str
=> tcx
.lang_items().str_impl(),
393 Slice
=> tcx
.lang_items().slice_impl(),
394 Array
=> tcx
.lang_items().slice_impl(),
397 RawPointer
=> tcx
.lang_items().const_ptr_impl(),
402 if let Some(did
) = did
{
404 inline
::build_impl(cx
, did
, None
, ret
);
411 fn to_src(&self, cx
: &DocContext
<'_
>) -> String
;
414 impl ToSource
for rustc_span
::Span
{
415 fn to_src(&self, cx
: &DocContext
<'_
>) -> String
{
416 debug
!("converting span {:?} to snippet", self.clean(cx
));
417 let sn
= match cx
.sess().source_map().span_to_snippet(*self) {
419 Err(_
) => String
::new(),
421 debug
!("got snippet {}", sn
);
426 pub fn name_from_pat(p
: &hir
::Pat
) -> String
{
428 debug
!("trying to get a name from pattern: {:?}", p
);
431 PatKind
::Wild
=> "_".to_string(),
432 PatKind
::Binding(_
, _
, ident
, _
) => ident
.to_string(),
433 PatKind
::TupleStruct(ref p
, ..) | PatKind
::Path(ref p
) => qpath_to_string(p
),
434 PatKind
::Struct(ref name
, ref fields
, etc
) => format
!(
436 qpath_to_string(name
),
439 .map(|fp
| format
!("{}: {}", fp
.ident
, name_from_pat(&fp
.pat
)))
440 .collect
::<Vec
<String
>>()
442 if etc { ", .." }
else { "" }
444 PatKind
::Or(ref pats
) => {
445 pats
.iter().map(|p
| name_from_pat(&**p
)).collect
::<Vec
<String
>>().join(" | ")
447 PatKind
::Tuple(ref elts
, _
) => format
!(
449 elts
.iter().map(|p
| name_from_pat(&**p
)).collect
::<Vec
<String
>>().join(", ")
451 PatKind
::Box(ref p
) => name_from_pat(&**p
),
452 PatKind
::Ref(ref p
, _
) => name_from_pat(&**p
),
453 PatKind
::Lit(..) => {
455 "tried to get argument name from PatKind::Lit, \
456 which is silly in function arguments"
460 PatKind
::Range(..) => panic
!(
461 "tried to get argument name from PatKind::Range, \
462 which is not allowed in function arguments"
464 PatKind
::Slice(ref begin
, ref mid
, ref end
) => {
465 let begin
= begin
.iter().map(|p
| name_from_pat(&**p
));
466 let mid
= mid
.as_ref().map(|p
| format
!("..{}", name_from_pat(&**p
))).into_iter();
467 let end
= end
.iter().map(|p
| name_from_pat(&**p
));
468 format
!("[{}]", begin
.chain(mid
).chain(end
).collect
::<Vec
<_
>>().join(", "))
473 pub fn print_const(cx
: &DocContext
<'_
>, n
: &'tcx ty
::Const
<'_
>) -> String
{
475 ty
::ConstKind
::Unevaluated(def_id
, _
, promoted
) => {
476 let mut s
= if let Some(hir_id
) = cx
.tcx
.hir().as_local_hir_id(def_id
) {
477 print_const_expr(cx
, cx
.tcx
.hir().body_owned_by(hir_id
))
479 inline
::print_inlined_const(cx
, def_id
)
481 if let Some(promoted
) = promoted
{
482 s
.push_str(&format
!("::{:?}", promoted
))
487 let mut s
= n
.to_string();
488 // array lengths are obviously usize
489 if s
.ends_with("usize") {
490 let n
= s
.len() - "usize".len();
492 if s
.ends_with(": ") {
493 let n
= s
.len() - ": ".len();
502 pub fn print_evaluated_const(cx
: &DocContext
<'_
>, def_id
: DefId
) -> Option
<String
> {
503 cx
.tcx
.const_eval_poly(def_id
).ok().and_then(|val
| {
504 let ty
= cx
.tcx
.type_of(def_id
);
505 match (val
, &ty
.kind
) {
506 (_
, &ty
::Ref(..)) => None
,
507 (ConstValue
::Scalar(_
), &ty
::Adt(_
, _
)) => None
,
508 (ConstValue
::Scalar(_
), _
) => {
509 let const_
= ty
::Const
::from_value(cx
.tcx
, val
, ty
);
510 Some(print_const_with_custom_print_scalar(cx
, const_
))
517 fn format_integer_with_underscore_sep(num
: &str) -> String
{
518 let num_chars
: Vec
<_
> = num
.chars().collect();
519 let num_start_index
= if num_chars
.get(0) == Some(&'
-'
) { 1 }
else { 0 }
;
521 num_chars
[..num_start_index
]
523 .chain(num_chars
[num_start_index
..].rchunks(3).rev().intersperse(&['_'
]).flatten())
527 fn print_const_with_custom_print_scalar(cx
: &DocContext
<'_
>, ct
: &'tcx ty
::Const
<'tcx
>) -> String
{
528 // Use a slightly different format for integer types which always shows the actual value.
529 // For all other types, fallback to the original `pretty_print_const`.
530 match (ct
.val
, &ct
.ty
.kind
) {
531 (ty
::ConstKind
::Value(ConstValue
::Scalar(Scalar
::Raw { data, .. }
)), ty
::Uint(ui
)) => {
532 format
!("{}{}", format_integer_with_underscore_sep(&data
.to_string()), ui
.name_str())
534 (ty
::ConstKind
::Value(ConstValue
::Scalar(Scalar
::Raw { data, .. }
)), ty
::Int(i
)) => {
535 let ty
= cx
.tcx
.lift(&ct
.ty
).unwrap();
536 let size
= cx
.tcx
.layout_of(ty
::ParamEnv
::empty().and(ty
)).unwrap().size
;
537 let sign_extended_data
= sign_extend(data
, size
) as i128
;
541 format_integer_with_underscore_sep(&sign_extended_data
.to_string()),
549 pub fn is_literal_expr(cx
: &DocContext
<'_
>, hir_id
: hir
::HirId
) -> bool
{
550 if let hir
::Node
::Expr(expr
) = cx
.tcx
.hir().get(hir_id
) {
551 if let hir
::ExprKind
::Lit(_
) = &expr
.kind
{
555 if let hir
::ExprKind
::Unary(hir
::UnOp
::UnNeg
, expr
) = &expr
.kind
{
556 if let hir
::ExprKind
::Lit(_
) = &expr
.kind
{
565 pub fn print_const_expr(cx
: &DocContext
<'_
>, body
: hir
::BodyId
) -> String
{
566 let value
= &cx
.tcx
.hir().body(body
).value
;
568 let snippet
= if !value
.span
.from_expansion() {
569 cx
.sess().source_map().span_to_snippet(value
.span
).ok()
574 snippet
.unwrap_or_else(|| rustc_hir_pretty
::id_to_string(&cx
.tcx
.hir(), body
.hir_id
))
577 /// Given a type Path, resolve it to a Type using the TyCtxt
578 pub fn resolve_type(cx
: &DocContext
<'_
>, path
: Path
, id
: hir
::HirId
) -> Type
{
579 debug
!("resolve_type({:?},{:?})", path
, id
);
581 let is_generic
= match path
.res
{
582 Res
::PrimTy(p
) => return Primitive(PrimitiveType
::from(p
)),
583 Res
::SelfTy(..) if path
.segments
.len() == 1 => {
584 return Generic(kw
::SelfUpper
.to_string());
586 Res
::Def(DefKind
::TyParam
, _
) if path
.segments
.len() == 1 => {
587 return Generic(format
!("{:#}", path
.print()));
589 Res
::SelfTy(..) | Res
::Def(DefKind
::TyParam
| DefKind
::AssocTy
, _
) => true,
592 let did
= register_res(&*cx
, path
.res
);
593 ResolvedPath { path, param_names: None, did, is_generic }
596 pub fn get_auto_trait_and_blanket_impls(
597 cx
: &DocContext
<'tcx
>,
599 param_env_def_id
: DefId
,
600 ) -> impl Iterator
<Item
= Item
> {
601 AutoTraitFinder
::new(cx
)
602 .get_auto_trait_impls(ty
, param_env_def_id
)
604 .chain(BlanketImplFinder
::new(cx
).get_blanket_impls(ty
, param_env_def_id
))
607 pub fn register_res(cx
: &DocContext
<'_
>, res
: Res
) -> DefId
{
608 debug
!("register_res({:?})", res
);
610 let (did
, kind
) = match res
{
611 Res
::Def(DefKind
::Fn
, i
) => (i
, TypeKind
::Function
),
612 Res
::Def(DefKind
::TyAlias
, i
) => (i
, TypeKind
::Typedef
),
613 Res
::Def(DefKind
::Enum
, i
) => (i
, TypeKind
::Enum
),
614 Res
::Def(DefKind
::Trait
, i
) => (i
, TypeKind
::Trait
),
615 Res
::Def(DefKind
::Struct
, i
) => (i
, TypeKind
::Struct
),
616 Res
::Def(DefKind
::Union
, i
) => (i
, TypeKind
::Union
),
617 Res
::Def(DefKind
::Mod
, i
) => (i
, TypeKind
::Module
),
618 Res
::Def(DefKind
::ForeignTy
, i
) => (i
, TypeKind
::Foreign
),
619 Res
::Def(DefKind
::Const
, i
) => (i
, TypeKind
::Const
),
620 Res
::Def(DefKind
::Static
, i
) => (i
, TypeKind
::Static
),
621 Res
::Def(DefKind
::Variant
, i
) => {
622 (cx
.tcx
.parent(i
).expect("cannot get parent def id"), TypeKind
::Enum
)
624 Res
::Def(DefKind
::Macro(mac_kind
), i
) => match mac_kind
{
625 MacroKind
::Bang
=> (i
, TypeKind
::Macro
),
626 MacroKind
::Attr
=> (i
, TypeKind
::Attr
),
627 MacroKind
::Derive
=> (i
, TypeKind
::Derive
),
629 Res
::Def(DefKind
::TraitAlias
, i
) => (i
, TypeKind
::TraitAlias
),
630 Res
::SelfTy(Some(def_id
), _
) => (def_id
, TypeKind
::Trait
),
631 Res
::SelfTy(_
, Some(impl_def_id
)) => return impl_def_id
,
632 _
=> return res
.def_id(),
637 inline
::record_extern_fqn(cx
, did
, kind
);
638 if let TypeKind
::Trait
= kind
{
639 inline
::record_extern_trait(cx
, did
);
644 pub fn resolve_use_source(cx
: &DocContext
<'_
>, path
: Path
) -> ImportSource
{
646 did
: if path
.res
.opt_def_id().is_none() { None }
else { Some(register_res(cx, path.res)) }
,
651 pub fn enter_impl_trait
<F
, R
>(cx
: &DocContext
<'_
>, f
: F
) -> R
655 let old_bounds
= mem
::take(&mut *cx
.impl_trait_bounds
.borrow_mut());
657 assert
!(cx
.impl_trait_bounds
.borrow().is_empty());
658 *cx
.impl_trait_bounds
.borrow_mut() = old_bounds
;