1
Fork 0

box ResolutionFailures on the heap

This decreases the size of the `Result`s being returned,
improving performance in the common case.
This commit is contained in:
Joshua Nelson 2020-09-11 13:29:55 -04:00
parent cd72d9029f
commit c213c68500

View file

@ -48,10 +48,16 @@ pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate {
} }
enum ErrorKind<'a> { enum ErrorKind<'a> {
Resolve(ResolutionFailure<'a>), Resolve(Box<ResolutionFailure<'a>>),
AnchorFailure(AnchorFailure), AnchorFailure(AnchorFailure),
} }
impl<'a> From<ResolutionFailure<'a>> for ErrorKind<'a> {
fn from(err: ResolutionFailure<'a>) -> Self {
ErrorKind::Resolve(box err)
}
}
#[derive(Debug)] #[derive(Debug)]
enum ResolutionFailure<'a> { enum ResolutionFailure<'a> {
/// This resolved, but with the wrong namespace. /// This resolved, but with the wrong namespace.
@ -142,10 +148,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
.expect("fold_item should ensure link is non-empty"); .expect("fold_item should ensure link is non-empty");
let variant_name = let variant_name =
// we're not sure this is a variant at all, so use the full string // we're not sure this is a variant at all, so use the full string
split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope{ split.next().map(|f| Symbol::intern(f)).ok_or_else(|| ResolutionFailure::NotInScope {
module_id, module_id,
name: path_str.into(), name: path_str.into(),
}))?; })?;
let path = split let path = split
.next() .next()
.map(|f| { .map(|f| {
@ -156,10 +162,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
} }
f.to_owned() f.to_owned()
}) })
.ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope { .ok_or_else(|| ResolutionFailure::NotInScope {
module_id, module_id,
name: variant_name.to_string().into(), name: variant_name.to_string().into(),
}))?; })?;
let ty_res = cx let ty_res = cx
.enter_resolver(|resolver| { .enter_resolver(|resolver| {
resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
@ -167,10 +173,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
.map(|(_, res)| res) .map(|(_, res)| res)
.unwrap_or(Res::Err); .unwrap_or(Res::Err);
if let Res::Err = ty_res { if let Res::Err = ty_res {
return Err(ErrorKind::Resolve(ResolutionFailure::NotInScope { return Err(ResolutionFailure::NotInScope { module_id, name: path.into() }.into());
module_id,
name: path.into(),
}));
} }
let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); let ty_res = ty_res.map_id(|_| panic!("unexpected node_id"));
match ty_res { match ty_res {
@ -184,7 +187,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
{ {
// This is just to let `fold_item` know that this shouldn't be considered; // This is just to let `fold_item` know that this shouldn't be considered;
// it's a bug for the error to make it to the user // it's a bug for the error to make it to the user
return Err(ErrorKind::Resolve(ResolutionFailure::Dummy)); return Err(ResolutionFailure::Dummy.into());
} }
match cx.tcx.type_of(did).kind() { match cx.tcx.type_of(did).kind() {
ty::Adt(def, _) if def.is_enum() => { ty::Adt(def, _) if def.is_enum() => {
@ -197,10 +200,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
)), )),
)) ))
} else { } else {
Err(ErrorKind::Resolve(ResolutionFailure::NotAVariant( Err(ResolutionFailure::NotAVariant(ty_res, variant_field_name).into())
ty_res,
variant_field_name,
)))
} }
} }
_ => unreachable!(), _ => unreachable!(),
@ -226,7 +226,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
// Even with the shorter path, it didn't resolve, so say that. // Even with the shorter path, it didn't resolve, so say that.
ResolutionFailure::NoAssocItem(ty_res, variant_name) ResolutionFailure::NoAssocItem(ty_res, variant_name)
}; };
Err(ErrorKind::Resolve(kind)) Err(kind.into())
} }
} }
} }
@ -344,7 +344,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
}; };
if value != (ns == ValueNS) { if value != (ns == ValueNS) {
return Err(ErrorKind::Resolve(ResolutionFailure::WrongNamespace(res, ns))); return Err(ResolutionFailure::WrongNamespace(res, ns).into());
} }
} else if let Some((path, prim)) = is_primitive(path_str, ns) { } else if let Some((path, prim)) = is_primitive(path_str, ns) {
if extra_fragment.is_some() { if extra_fragment.is_some() {
@ -373,16 +373,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
// So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
.ok_or_else(|| { .ok_or_else(|| {
debug!("found no `::`, assumming {} was correctly not in scope", item_name); debug!("found no `::`, assumming {} was correctly not in scope", item_name);
ErrorKind::Resolve(ResolutionFailure::NotInScope { ResolutionFailure::NotInScope { module_id, name: item_name.to_string().into() }
module_id,
name: item_name.to_string().into(),
})
})?; })?;
if let Some((path, prim)) = is_primitive(&path_root, TypeNS) { if let Some((path, prim)) = is_primitive(&path_root, TypeNS) {
let impls = primitive_impl(cx, &path).ok_or_else(|| { let impls = primitive_impl(cx, &path)
ErrorKind::Resolve(ResolutionFailure::NoPrimitiveImpl(prim, path_root.into())) .ok_or_else(|| ResolutionFailure::NoPrimitiveImpl(prim, path_root.into()))?;
})?;
for &impl_ in impls { for &impl_ in impls {
let link = cx let link = cx
.tcx .tcx
@ -409,11 +405,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
item_name, item_name,
ns.descr() ns.descr()
); );
return Err(ErrorKind::Resolve(ResolutionFailure::NoPrimitiveAssocItem { return Err(ResolutionFailure::NoPrimitiveAssocItem {
res: prim, res: prim,
prim_name: path, prim_name: path,
assoc_item: item_name, assoc_item: item_name,
})); }
.into());
} }
let ty_res = cx let ty_res = cx
@ -445,7 +442,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
} }
ResolutionFailure::NotInScope { module_id, name: path_root.into() } ResolutionFailure::NotInScope { module_id, name: path_root.into() }
}); });
Err(ErrorKind::Resolve(kind)) Err(kind.into())
}; };
} }
Ok(res) => res, Ok(res) => res,
@ -548,9 +545,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
} }
} else { } else {
// We already know this isn't in ValueNS, so no need to check variant_field // We already know this isn't in ValueNS, so no need to check variant_field
return Err(ErrorKind::Resolve(ResolutionFailure::NoAssocItem( return Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into());
ty_res, item_name,
)));
} }
} }
Res::Def(DefKind::Trait, did) => cx Res::Def(DefKind::Trait, did) => cx
@ -585,12 +580,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
if ns == Namespace::ValueNS { if ns == Namespace::ValueNS {
self.variant_field(path_str, current_item, module_id, extra_fragment) self.variant_field(path_str, current_item, module_id, extra_fragment)
} else { } else {
Err(ErrorKind::Resolve(ResolutionFailure::NoAssocItem(ty_res, item_name))) Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into())
} }
}) })
} else { } else {
debug!("attempting to resolve item without parent module: {}", path_str); debug!("attempting to resolve item without parent module: {}", path_str);
Err(ErrorKind::Resolve(ResolutionFailure::NoParentItem)) Err(ResolutionFailure::NoParentItem.into())
} }
} }
@ -611,7 +606,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
let check_full_res_inner = |this: &Self, result: Result<Res, ErrorKind<'_>>| { let check_full_res_inner = |this: &Self, result: Result<Res, ErrorKind<'_>>| {
let res = match result { let res = match result {
Ok(res) => Some(res), Ok(res) => Some(res),
Err(ErrorKind::Resolve(kind)) => kind.full_res(), Err(ErrorKind::Resolve(box kind)) => kind.full_res(),
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => { Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => {
Some(res) Some(res)
} }
@ -626,7 +621,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
}; };
let check_full_res_macro = |this: &Self| { let check_full_res_macro = |this: &Self| {
let result = this.macro_resolve(path_str, base_node); let result = this.macro_resolve(path_str, base_node);
check_full_res_inner(this, result.map_err(ErrorKind::Resolve)) check_full_res_inner(this, result.map_err(ErrorKind::from))
}; };
match ns { match ns {
Namespace::MacroNS => check_full_res_macro(self), Namespace::MacroNS => check_full_res_macro(self),
@ -970,7 +965,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
match self.resolve(path_str, ns, &current_item, base_node, &extra_fragment) match self.resolve(path_str, ns, &current_item, base_node, &extra_fragment)
{ {
Ok(res) => res, Ok(res) => res,
Err(ErrorKind::Resolve(mut kind)) => { Err(ErrorKind::Resolve(box mut kind)) => {
// We only looked in one namespace. Try to give a better error if possible. // We only looked in one namespace. Try to give a better error if possible.
if kind.full_res().is_none() { if kind.full_res().is_none() {
let other_ns = if ns == ValueNS { TypeNS } else { ValueNS }; let other_ns = if ns == ValueNS { TypeNS } else { ValueNS };
@ -1028,7 +1023,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); anchor_failure(cx, &item, &ori_link, &dox, link_range, msg);
continue; continue;
} }
Err(ErrorKind::Resolve(kind)) => Err(kind), Err(ErrorKind::Resolve(box kind)) => Err(kind),
}, },
value_ns: match self.resolve( value_ns: match self.resolve(
path_str, path_str,
@ -1042,7 +1037,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); anchor_failure(cx, &item, &ori_link, &dox, link_range, msg);
continue; continue;
} }
Err(ErrorKind::Resolve(kind)) => Err(kind), Err(ErrorKind::Resolve(box kind)) => Err(kind),
} }
.and_then(|(res, fragment)| { .and_then(|(res, fragment)| {
// Constructors are picked up in the type namespace. // Constructors are picked up in the type namespace.
@ -1816,7 +1811,7 @@ fn handle_variant(
let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) { let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) {
parent parent
} else { } else {
return Err(ErrorKind::Resolve(ResolutionFailure::NoParentItem)); return Err(ResolutionFailure::NoParentItem.into());
}; };
let parent_def = Res::Def(DefKind::Enum, parent); let parent_def = Res::Def(DefKind::Enum, parent);
let variant = cx.tcx.expect_variant_res(res); let variant = cx.tcx.expect_variant_res(res);