Skip to content

rustdoc: Stop cloning the resolver #83761

Closed
@jyn514

Description

@jyn514

Rustdoc currently creates a copy of the resolver to use for intra-doc links:

rust/src/librustdoc/core.rs

Lines 350 to 354 in d474075

crate fn create_resolver<'a>(
externs: config::Externs,
queries: &Queries<'a>,
sess: &Session,
) -> Rc<RefCell<interface::BoxedResolver>> {

This is a Terrible, Horrible, No Good, Very Bad Idea. In particular, it causes rustdoc's copy of the resolver and the TyCtxt to disagree about what crates exist:

It's also distorting rustc_resolve, since not all of the outputs make sense to clone in the first place: #65625 (comment)

We should refactor rustdoc somehow to allow getting rid of Resolver::clone_outputs. @petrochenkov suggests moving anything that needs to touch the resolver before HIR lowering: #68427 (comment).

@petrochenkov what do you think about @eddyb's comment in #65625 (comment) ?

Why would cloning be needed? Is this that support for resolving things after rustc_resolve finishes?
In that case I'm not sure why we need to clone the outputs - is it to be able to keep the original resolver around?

Would it be possible for lower_to_hir to stop stealing the resolver?

let resolver = peeked.1.steal();

Then rustdoc wouldn't need to clone it in the first place, it could just call queries.expansion().peek().1 whenever it needs access to the resolver.

See #68427 for previous discussion.


Implementation History

  • Initial "early crate loader": rustdoc: Don't load all extern crates unconditionally #83738
  • Don't require clean::Items before resolving intra-doc links: rustdoc: Store intra-doc links in Cache instead of on items directly #83833
  • Separate type-relative resolution from path resolution (at least somewhat): rustdoc: Cleanup handling of associated items for intra-doc links #83849
  • Move early loader into collect_intra_doc_links: rustdoc: Move crate loader to collect_intra_doc_links::early  #84101
  • Move all path resolution from late to early module and add new field on DocContext for partially resolved links
    • Change preprocess_link to also take into account the hacks for Self:: and crate:
      // FIXME(jynelson): this shouldn't go through stringification, rustdoc should just use the DefId directly
      ,
      let resolved_self;
      // replace `Self` with suitable item's parent name
      let is_lone_self = path_str == "Self";
      let is_lone_crate = path_str == "crate";
      if path_str.starts_with("Self::") || is_lone_self {
      if let Some(ref name) = self_name {
      if is_lone_self {
      path_str = name;
      } else {
      resolved_self = format!("{}::{}", name, &path_str[6..]);
      path_str = &resolved_self;
      }
      }
      } else if path_str.starts_with("crate::") || is_lone_crate {
      use rustc_span::def_id::CRATE_DEF_INDEX;
      // HACK(jynelson): rustc_resolve thinks that `crate` is the crate currently being documented.
      // But rustdoc wants it to mean the crate this item was originally present in.
      // To work around this, remove it and resolve relative to the crate root instead.
      // HACK(jynelson)(2): If we just strip `crate::` then suddenly primitives become ambiguous
      // (consider `crate::char`). Instead, change it to `self::`. This works because 'self' is now the crate root.
      // FIXME(#78696): This doesn't always work.
      if is_lone_crate {
      path_str = "self";
      } else {
      resolved_self = format!("self::{}", &path_str["crate::".len()..]);
      path_str = &resolved_self;
      }
      module_id = DefId { krate, index: CRATE_DEF_INDEX };
      }

Metadata

Metadata

Assignees

Labels

A-resolveArea: Name/path resolution done by `rustc_resolve` specificallyC-cleanupCategory: PRs that clean code up or issues documenting cleanup.T-rustdocRelevant to the rustdoc team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions