summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_resolve
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_resolve')
-rw-r--r--compiler/rustc_resolve/Cargo.toml3
-rw-r--r--compiler/rustc_resolve/locales/en-US.ftl211
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs126
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs145
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs10
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs226
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs42
-rw-r--r--compiler/rustc_resolve/src/errors.rs14
-rw-r--r--compiler/rustc_resolve/src/ident.rs23
-rw-r--r--compiler/rustc_resolve/src/imports.rs163
-rw-r--r--compiler/rustc_resolve/src/late.rs265
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs142
-rw-r--r--compiler/rustc_resolve/src/lib.rs309
-rw-r--r--compiler/rustc_resolve/src/macros.rs69
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs388
15 files changed, 1481 insertions, 655 deletions
diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml
index 7c3a0f8f2..5c4ec44d2 100644
--- a/compiler/rustc_resolve/Cargo.toml
+++ b/compiler/rustc_resolve/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
[dependencies]
bitflags = "1.2.1"
+pulldown-cmark = { version = "0.9.2", default-features = false }
rustc_arena = { path = "../rustc_arena" }
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
@@ -24,5 +25,5 @@ rustc_query_system = { path = "../rustc_query_system" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-thin-vec = "0.2.8"
+thin-vec = "0.2.12"
tracing = "0.1"
diff --git a/compiler/rustc_resolve/locales/en-US.ftl b/compiler/rustc_resolve/locales/en-US.ftl
new file mode 100644
index 000000000..817bb83ed
--- /dev/null
+++ b/compiler/rustc_resolve/locales/en-US.ftl
@@ -0,0 +1,211 @@
+resolve_parent_module_reset_for_binding =
+ parent module is reset for binding
+
+resolve_ampersand_used_without_explicit_lifetime_name =
+ `&` without an explicit lifetime name cannot be used here
+ .note = explicit lifetime name needed here
+
+resolve_underscore_lifetime_name_cannot_be_used_here =
+ `'_` cannot be used here
+ .note = `'_` is a reserved lifetime name
+
+resolve_crate_may_not_be_imported =
+ `$crate` may not be imported
+
+resolve_crate_root_imports_must_be_named_explicitly =
+ crate root imports need to be explicitly named: `use crate as name;`
+
+resolve_generic_params_from_outer_function =
+ can't use generic parameters from outer function
+ .label = use of generic parameter from outer function
+ .suggestion = try using a local generic parameter instead
+
+resolve_self_type_implicitly_declared_by_impl =
+ `Self` type implicitly declared here, by this `impl`
+
+resolve_cannot_use_self_type_here =
+ can't use `Self` here
+
+resolve_use_a_type_here_instead =
+ use a type here instead
+
+resolve_type_param_from_outer_fn =
+ type parameter from outer function
+
+resolve_const_param_from_outer_fn =
+ const parameter from outer function
+
+resolve_try_using_local_generic_parameter =
+ try using a local generic parameter instead
+
+resolve_try_adding_local_generic_param_on_method =
+ try adding a local generic parameter in this method instead
+
+resolve_help_try_using_local_generic_param =
+ try using a local generic paramter instead
+
+resolve_name_is_already_used_as_generic_parameter =
+ the name `{$name}` is already used for a generic parameter in this item's generic parameters
+ .label = already used
+ .first_use_of_name = first use of `{$name}`
+
+resolve_method_not_member_of_trait =
+ method `{$method}` is not a member of trait `{$trait_}`
+ .label = not a member of trait `{$trait_}`
+
+resolve_associated_fn_with_similar_name_exists =
+ there is an associated function with a similar name
+
+resolve_type_not_member_of_trait =
+ type `{$type_}` is not a member of trait `{$trait_}`
+ .label = not a member of trait `{$trait_}`
+
+resolve_associated_type_with_similar_name_exists =
+ there is an associated type with a similar name
+
+resolve_const_not_member_of_trait =
+ const `{$const_}` is not a member of trait `{$trait_}`
+ .label = not a member of trait `{$trait_}`
+
+resolve_associated_const_with_similar_name_exists =
+ there is an associated constant with a similar name
+
+resolve_variable_bound_with_different_mode =
+ variable `{$variable_name}` is bound inconsistently across alternatives separated by `|`
+ .label = bound in different ways
+ .first_binding_span = first binding
+
+resolve_ident_bound_more_than_once_in_parameter_list =
+ identifier `{$identifier}` is bound more than once in this parameter list
+ .label = used as parameter more than once
+
+resolve_ident_bound_more_than_once_in_same_pattern =
+ identifier `{$identifier}` is bound more than once in the same pattern
+ .label = used in a pattern more than once
+
+resolve_undeclared_label =
+ use of undeclared label `{$name}`
+ .label = undeclared label `{$name}`
+
+resolve_label_with_similar_name_reachable =
+ a label with a similar name is reachable
+
+resolve_try_using_similarly_named_label =
+ try using similarly named label
+
+resolve_unreachable_label_with_similar_name_exists =
+ a label with a similar name exists but is unreachable
+
+resolve_self_import_can_only_appear_once_in_the_list =
+ `self` import can only appear once in an import list
+ .label = can only appear once in an import list
+
+resolve_self_import_only_in_import_list_with_non_empty_prefix =
+ `self` import can only appear in an import list with a non-empty prefix
+ .label = can only appear in an import list with a non-empty prefix
+
+resolve_cannot_capture_dynamic_environment_in_fn_item =
+ can't capture dynamic environment in a fn item
+ .help = use the `|| {"{"} ... {"}"}` closure form instead
+
+resolve_attempt_to_use_non_constant_value_in_constant =
+ attempt to use a non-constant value in a constant
+
+resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion =
+ consider using `{$suggestion}` instead of `{$current}`
+
+resolve_attempt_to_use_non_constant_value_in_constant_label_with_suggestion =
+ non-constant value
+
+resolve_attempt_to_use_non_constant_value_in_constant_without_suggestion =
+ this would need to be a `{$suggestion}`
+
+resolve_self_imports_only_allowed_within =
+ `self` imports are only allowed within a {"{"} {"}"} list
+
+resolve_self_imports_only_allowed_within_suggestion =
+ consider importing the module directly
+
+resolve_self_imports_only_allowed_within_multipart_suggestion =
+ alternatively, use the multi-path `use` syntax to import `self`
+
+resolve_binding_shadows_something_unacceptable =
+ {$shadowing_binding}s cannot shadow {$shadowed_binding}s
+ .label = cannot be named the same as {$article} {$shadowed_binding}
+ .label_shadowed_binding = the {$shadowed_binding} `{$name}` is {$participle} here
+
+resolve_binding_shadows_something_unacceptable_suggestion =
+ try specify the pattern arguments
+
+resolve_forward_declared_generic_param =
+ generic parameters with a default cannot use forward declared identifiers
+ .label = defaulted generic parameters cannot be forward declared
+
+resolve_param_in_ty_of_const_param =
+ the type of const parameters must not depend on other generic parameters
+ .label = the type must not depend on the parameter `{$name}`
+
+resolve_self_in_generic_param_default =
+ generic parameters cannot use `Self` in their defaults
+ .label = `Self` in generic parameter default
+
+resolve_param_in_non_trivial_anon_const =
+ generic parameters may not be used in const operations
+ .label = cannot perform const operation using `{$name}`
+
+resolve_param_in_non_trivial_anon_const_help =
+ use `#![feature(generic_const_exprs)]` to allow generic const expressions
+
+resolve_param_in_non_trivial_anon_const_sub_type =
+ type parameters may not be used in const expressions
+
+resolve_param_in_non_trivial_anon_const_sub_non_type =
+ const parameters may only be used as standalone arguments, i.e. `{$name}`
+
+resolve_unreachable_label =
+ use of unreachable label `{$name}`
+ .label = unreachable label `{$name}`
+ .label_definition_span = unreachable label defined here
+ .note = labels are unreachable through functions, closures, async blocks and modules
+
+resolve_unreachable_label_suggestion_use_similarly_named =
+ try using similarly named label
+
+resolve_unreachable_label_similar_name_reachable =
+ a label with a similar name is reachable
+
+resolve_unreachable_label_similar_name_unreachable =
+ a label with a similar name exists but is also unreachable
+
+resolve_trait_impl_mismatch =
+ item `{$name}` is an associated {$kind}, which doesn't match its trait `{$trait_path}`
+ .label = does not match trait
+ .label_trait_item = item in trait
+
+resolve_invalid_asm_sym =
+ invalid `sym` operand
+ .label = is a local variable
+ .help = `sym` operands must refer to either a function or a static
+
+resolve_trait_impl_duplicate =
+ duplicate definitions with name `{$name}`:
+ .label = duplicate definition
+ .old_span_label = previous definition here
+ .trait_item_span = item in trait
+
+resolve_relative_2018 =
+ relative paths are not supported in visibilities in 2018 edition or later
+ .suggestion = try
+
+resolve_ancestor_only =
+ visibilities can only be restricted to ancestor modules
+
+resolve_expected_found =
+ expected module, found {$res} `{$path_str}`
+ .label = not a module
+
+resolve_indeterminate =
+ cannot determine resolution for the visibility
+
+resolve_module_only =
+ visibility must resolve to a module
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index b1b04c92a..b1e023f2c 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -65,7 +65,7 @@ impl<'a, Id: Into<DefId>> ToNameBinding<'a> for (Res, ty::Visibility<Id>, Span,
}
}
-impl<'a> Resolver<'a> {
+impl<'a, 'tcx> Resolver<'a, 'tcx> {
/// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
/// otherwise, reports an error.
pub(crate) fn define<T>(&mut self, parent: Module<'a>, ident: Ident, ns: Namespace, def: T)
@@ -95,7 +95,7 @@ impl<'a> Resolver<'a> {
/// Reachable macros with block module parents exist due to `#[macro_export] macro_rules!`,
/// but they cannot use def-site hygiene, so the assumption holds
/// (<https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508>).
- pub fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'a> {
+ pub(crate) fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'a> {
loop {
match self.get_module(def_id) {
Some(module) => return module,
@@ -104,7 +104,7 @@ impl<'a> Resolver<'a> {
}
}
- pub fn expect_module(&mut self, def_id: DefId) -> Module<'a> {
+ pub(crate) fn expect_module(&mut self, def_id: DefId) -> Module<'a> {
self.get_module(def_id).expect("argument `DefId` is not a module")
}
@@ -130,11 +130,13 @@ impl<'a> Resolver<'a> {
def_key.disambiguated_data.data.get_opt_name().expect("module without name")
};
+ let expn_id = self.cstore().module_expansion_untracked(def_id, &self.tcx.sess);
+ let span = self.cstore().get_span_untracked(def_id, &self.tcx.sess);
Some(self.new_module(
parent,
ModuleKind::Def(def_kind, def_id, name),
- self.cstore().module_expansion_untracked(def_id, &self.session),
- self.cstore().get_span_untracked(def_id, &self.session),
+ expn_id,
+ span,
// FIXME: Account for `#[no_implicit_prelude]` attributes.
parent.map_or(false, |module| module.no_implicit_prelude),
))
@@ -179,7 +181,8 @@ impl<'a> Resolver<'a> {
return macro_data.clone();
}
- let (ext, macro_rules) = match self.cstore().load_macro_untracked(def_id, &self.session) {
+ let load_macro_untracked = self.cstore().load_macro_untracked(def_id, &self.tcx.sess);
+ let (ext, macro_rules) = match load_macro_untracked {
LoadedMacro::MacroDef(item, edition) => (
Lrc::new(self.compile_macro(&item, edition).0),
matches!(item.kind, ItemKind::MacroDef(def) if def.macro_rules),
@@ -204,9 +207,9 @@ impl<'a> Resolver<'a> {
}
pub(crate) fn build_reduced_graph_external(&mut self, module: Module<'a>) {
- for child in
- Vec::from_iter(self.cstore().module_children_untracked(module.def_id(), self.session))
- {
+ let children =
+ Vec::from_iter(self.cstore().module_children_untracked(module.def_id(), self.tcx.sess));
+ for child in children {
let parent_scope = ParentScope::module(module, self);
BuildReducedGraphVisitor { r: self, parent_scope }
.build_reduced_graph_for_external_crate_res(child);
@@ -214,18 +217,18 @@ impl<'a> Resolver<'a> {
}
}
-struct BuildReducedGraphVisitor<'a, 'b> {
- r: &'b mut Resolver<'a>,
+struct BuildReducedGraphVisitor<'a, 'b, 'tcx> {
+ r: &'b mut Resolver<'a, 'tcx>,
parent_scope: ParentScope<'a>,
}
-impl<'a> AsMut<Resolver<'a>> for BuildReducedGraphVisitor<'a, '_> {
- fn as_mut(&mut self) -> &mut Resolver<'a> {
+impl<'a, 'tcx> AsMut<Resolver<'a, 'tcx>> for BuildReducedGraphVisitor<'a, '_, 'tcx> {
+ fn as_mut(&mut self) -> &mut Resolver<'a, 'tcx> {
self.r
}
}
-impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
+impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility {
self.try_resolve_visibility(vis, true).unwrap_or_else(|err| {
self.r.report_vis_error(err);
@@ -265,7 +268,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
let ident = path.segments.get(0).expect("empty path in visibility").ident;
let crate_root = if ident.is_path_segment_keyword() {
None
- } else if ident.span.rust_2015() {
+ } else if ident.span.is_rust_2015() {
Some(Segment::from_ident(Ident::new(
kw::PathRoot,
path.span.shrink_to_lo().with_ctxt(ident.span.ctxt()),
@@ -298,14 +301,15 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
self.r.record_partial_res(id, PartialRes::new(res));
}
if module.is_normal() {
- if res == Res::Err {
- Ok(ty::Visibility::Public)
- } else {
- let vis = ty::Visibility::Restricted(res.def_id());
- if self.r.is_accessible_from(vis, parent_scope.module) {
- Ok(vis.expect_local())
- } else {
- Err(VisResolutionError::AncestorOnly(path.span))
+ match res {
+ Res::Err => Ok(ty::Visibility::Public),
+ _ => {
+ let vis = ty::Visibility::Restricted(res.def_id());
+ if self.r.is_accessible_from(vis, parent_scope.module) {
+ Ok(vis.expect_local())
+ } else {
+ Err(VisResolutionError::AncestorOnly(path.span))
+ }
}
}
} else {
@@ -345,7 +349,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
fn insert_field_names_extern(&mut self, def_id: DefId) {
let field_names =
- self.r.cstore().struct_field_names_untracked(def_id, self.r.session).collect();
+ self.r.cstore().struct_field_names_untracked(def_id, self.r.tcx.sess).collect();
self.r.field_names.insert(def_id, field_names);
}
@@ -434,10 +438,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
// appears, so imports in braced groups can have roots prepended independently.
let is_glob = matches!(use_tree.kind, ast::UseTreeKind::Glob);
let crate_root = match prefix_iter.peek() {
- Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.rust_2015() => {
+ Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.is_rust_2015() => {
Some(seg.ident.span.ctxt())
}
- None if is_glob && use_tree.span.rust_2015() => Some(use_tree.span.ctxt()),
+ None if is_glob && use_tree.span.is_rust_2015() => Some(use_tree.span.ctxt()),
_ => None,
}
.map(|ctxt| {
@@ -538,14 +542,15 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
}
self.r
- .session
+ .tcx
+ .sess
.struct_span_err(item.span, "`$crate` may not be imported")
.emit();
}
}
if ident.name == kw::Crate {
- self.r.session.span_err(
+ self.r.tcx.sess.span_err(
ident.span,
"crate root imports need to be explicitly named: \
`use crate as name;`",
@@ -574,7 +579,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
}
ast::UseTreeKind::Glob => {
let kind = ImportKind::Glob {
- is_prelude: self.r.session.contains_name(&item.attrs, sym::prelude_import),
+ is_prelude: self.r.tcx.sess.contains_name(&item.attrs, sym::prelude_import),
max_vis: Cell::new(None),
id,
};
@@ -689,7 +694,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
expansion.to_expn_id(),
item.span,
parent.no_implicit_prelude
- || self.r.session.contains_name(&item.attrs, sym::no_implicit_prelude),
+ || self.r.tcx.sess.contains_name(&item.attrs, sym::no_implicit_prelude),
);
self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
@@ -754,7 +759,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
// If the structure is marked as non_exhaustive then lower the visibility
// to within the crate.
let mut ctor_vis = if vis.is_public()
- && self.r.session.contains_name(&item.attrs, sym::non_exhaustive)
+ && self.r.tcx.sess.contains_name(&item.attrs, sym::non_exhaustive)
{
ty::Visibility::Restricted(CRATE_DEF_ID)
} else {
@@ -836,7 +841,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
let (used, module, binding) = if orig_name.is_none() && ident.name == kw::SelfLower {
self.r
- .session
+ .tcx
+ .sess
.struct_span_err(item.span, "`extern crate self;` requires renaming")
.span_suggestion(
item.span,
@@ -849,7 +855,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
} else if orig_name == Some(kw::SelfLower) {
Some(self.r.graph_root)
} else {
- let crate_id = self.r.crate_loader().process_extern_crate(item, local_def_id);
+ let tcx = self.r.tcx;
+ let crate_id = self.r.crate_loader(|c| {
+ c.process_extern_crate(item, local_def_id, &tcx.definitions_untracked())
+ });
crate_id.map(|crate_id| {
self.r.extern_crate_map.insert(local_def_id, crate_id);
self.r.expect_module(crate_id.as_def_id())
@@ -886,7 +895,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
{
let msg = "macro-expanded `extern crate` items cannot \
shadow names passed with `--extern`";
- self.r.session.span_err(item.span, msg);
+ self.r.tcx.sess.span_err(item.span, msg);
}
}
let entry = self.r.extern_prelude.entry(ident.normalize_to_macros_2_0()).or_insert(
@@ -986,7 +995,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
| DefKind::LifetimeParam
| DefKind::GlobalAsm
| DefKind::Closure
- | DefKind::Impl
+ | DefKind::Impl { .. }
| DefKind::Generator,
_,
)
@@ -997,23 +1006,26 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
| Res::Err => bug!("unexpected resolution: {:?}", res),
}
// Record some extra data for better diagnostics.
- let cstore = self.r.cstore();
match res {
Res::Def(DefKind::Struct, def_id) => {
+ let cstore = self.r.cstore();
if let Some((ctor_kind, ctor_def_id)) = cstore.ctor_untracked(def_id) {
let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
let ctor_vis = cstore.visibility_untracked(ctor_def_id);
let field_visibilities =
cstore.struct_field_visibilities_untracked(def_id).collect();
+ drop(cstore);
self.r
.struct_constructors
.insert(def_id, (ctor_res, ctor_vis, field_visibilities));
+ } else {
+ drop(cstore);
}
self.insert_field_names_extern(def_id)
}
Res::Def(DefKind::Union, def_id) => self.insert_field_names_extern(def_id),
Res::Def(DefKind::AssocFn, def_id) => {
- if cstore.fn_has_self_parameter_untracked(def_id, self.r.session) {
+ if self.r.cstore().fn_has_self_parameter_untracked(def_id, self.r.tcx.sess) {
self.r.has_self.insert(def_id);
}
}
@@ -1032,7 +1044,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
let msg = format!("`{}` is already in scope", name);
let note =
"macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";
- self.r.session.struct_span_err(span, &msg).note(note).emit();
+ self.r.tcx.sess.struct_span_err(span, &msg).note(note).emit();
}
}
@@ -1044,7 +1056,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
if attr.has_name(sym::macro_use) {
if self.parent_scope.module.parent.is_some() {
struct_span_err!(
- self.r.session,
+ self.r.tcx.sess,
item.span,
E0468,
"an `extern crate` loading macros must be at the crate root"
@@ -1054,7 +1066,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
if let ItemKind::ExternCrate(Some(orig_name)) = item.kind {
if orig_name == kw::SelfLower {
self.r
- .session
+ .tcx
+ .sess
.struct_span_err(
attr.span,
"`#[macro_use]` is not supported on `extern crate self`",
@@ -1063,7 +1076,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
}
}
let ill_formed = |span| {
- struct_span_err!(self.r.session, span, E0466, "bad macro import").emit();
+ struct_span_err!(self.r.tcx.sess, span, E0466, "bad macro import").emit();
};
match attr.meta() {
Some(meta) => match meta.kind {
@@ -1134,8 +1147,13 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
allow_shadowing,
);
} else {
- struct_span_err!(self.r.session, ident.span, E0469, "imported macro not found")
- .emit();
+ struct_span_err!(
+ self.r.tcx.sess,
+ ident.span,
+ E0469,
+ "imported macro not found"
+ )
+ .emit();
}
}
}
@@ -1147,7 +1165,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
for attr in attrs {
if attr.has_name(sym::macro_escape) {
let msg = "`#[macro_escape]` is a deprecated synonym for `#[macro_use]`";
- let mut err = self.r.session.struct_span_warn(attr.span, msg);
+ let mut err = self.r.tcx.sess.struct_span_warn(attr.span, msg);
if let ast::AttrStyle::Inner = attr.style {
err.help("try an outer attribute: `#[macro_use]`").emit();
} else {
@@ -1158,7 +1176,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
}
if !attr.is_word() {
- self.r.session.span_err(attr.span, "arguments to `macro_use` are not allowed here");
+ self.r
+ .tcx
+ .sess
+ .span_err(attr.span, "arguments to `macro_use` are not allowed here");
}
return true;
}
@@ -1182,11 +1203,11 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
}
fn proc_macro_stub(&self, item: &ast::Item) -> Option<(MacroKind, Ident, Span)> {
- if self.r.session.contains_name(&item.attrs, sym::proc_macro) {
+ if self.r.tcx.sess.contains_name(&item.attrs, sym::proc_macro) {
return Some((MacroKind::Bang, item.ident, item.span));
- } else if self.r.session.contains_name(&item.attrs, sym::proc_macro_attribute) {
+ } else if self.r.tcx.sess.contains_name(&item.attrs, sym::proc_macro_attribute) {
return Some((MacroKind::Attr, item.ident, item.span));
- } else if let Some(attr) = self.r.session.find_by_name(&item.attrs, sym::proc_macro_derive)
+ } else if let Some(attr) = self.r.tcx.sess.find_by_name(&item.attrs, sym::proc_macro_derive)
{
if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) {
if let Some(ident) = nested_meta.ident() {
@@ -1221,7 +1242,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
let def_id = self.r.local_def_id(item.id);
let (ext, ident, span, macro_rules, rule_spans) = match &item.kind {
ItemKind::MacroDef(def) => {
- let (ext, rule_spans) = self.r.compile_macro(item, self.r.session.edition());
+ let (ext, rule_spans) = self.r.compile_macro(item, self.r.tcx.sess.edition());
let ext = Lrc::new(ext);
(ext, item.ident, item.span, def.macro_rules, rule_spans)
}
@@ -1242,7 +1263,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
if macro_rules {
let ident = ident.normalize_to_macros_2_0();
self.r.macro_names.insert(ident);
- let is_macro_export = self.r.session.contains_name(&item.attrs, sym::macro_export);
+ let is_macro_export = self.r.tcx.sess.contains_name(&item.attrs, sym::macro_export);
let vis = if is_macro_export {
ty::Visibility::Public
} else {
@@ -1250,6 +1271,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
};
let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas);
self.r.set_binding_parent_module(binding, parent_scope.module);
+ self.r.all_macro_rules.insert(ident.name, res);
if is_macro_export {
let import = self.r.arenas.alloc_import(Import {
kind: ImportKind::MacroExport,
@@ -1313,7 +1335,7 @@ macro_rules! method {
};
}
-impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
+impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
method!(visit_expr: ast::Expr, ast::ExprKind::MacCall, walk_expr);
method!(visit_pat: ast::Pat, ast::PatKind::MacCall, walk_pat);
method!(visit_ty: ast::Ty, ast::TyKind::MacCall, walk_ty);
@@ -1505,7 +1527,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
// If the variant is marked as non_exhaustive then lower the visibility to within the crate.
let ctor_vis = if vis.is_public()
- && self.r.session.contains_name(&variant.attrs, sym::non_exhaustive)
+ && self.r.tcx.sess.contains_name(&variant.attrs, sym::non_exhaustive)
{
ty::Visibility::Restricted(CRATE_DEF_ID)
} else {
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index eae4c9992..b2578e4c4 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -29,11 +29,12 @@ use crate::Resolver;
use rustc_ast as ast;
use rustc_ast::visit::{self, Visitor};
-use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_data_structures::unord::UnordSet;
use rustc_errors::{pluralize, MultiSpan};
-use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_IMPORTS};
+use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS};
use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_span::symbol::Ident;
use rustc_span::{Span, DUMMY_SP};
struct UnusedImport<'a> {
@@ -49,16 +50,33 @@ impl<'a> UnusedImport<'a> {
}
}
-struct UnusedImportCheckVisitor<'a, 'b> {
- r: &'a mut Resolver<'b>,
+struct UnusedImportCheckVisitor<'a, 'b, 'tcx> {
+ r: &'a mut Resolver<'b, 'tcx>,
/// All the (so far) unused imports, grouped path list
unused_imports: FxIndexMap<ast::NodeId, UnusedImport<'a>>,
+ extern_crate_items: Vec<ExternCrateToLint>,
base_use_tree: Option<&'a ast::UseTree>,
base_id: ast::NodeId,
item_span: Span,
}
-impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
+struct ExternCrateToLint {
+ id: ast::NodeId,
+ /// Span from the item
+ span: Span,
+ /// Span to use to suggest complete removal.
+ span_with_attributes: Span,
+ /// Span of the visibility, if any.
+ vis_span: Span,
+ /// Whether the item has attrs.
+ has_attrs: bool,
+ /// Name used to refer to the crate.
+ ident: Ident,
+ /// Whether the statement renames the crate `extern crate orig_name as new_name;`.
+ renames: bool,
+}
+
+impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
// We have information about whether `use` (import) items are actually
// used now. If an import is not used at all, we signal a lint error.
fn check_import(&mut self, id: ast::NodeId) {
@@ -94,20 +112,29 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
}
}
-impl<'a, 'b> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b> {
+impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
fn visit_item(&mut self, item: &'a ast::Item) {
- self.item_span = item.span_with_attributes();
-
- // Ignore is_public import statements because there's no way to be sure
- // whether they're used or not. Also ignore imports with a dummy span
- // because this means that they were generated in some fashion by the
- // compiler and we don't need to consider them.
- if let ast::ItemKind::Use(..) = item.kind {
- if item.vis.kind.is_pub() || item.span.is_dummy() {
- return;
+ match item.kind {
+ // Ignore is_public import statements because there's no way to be sure
+ // whether they're used or not. Also ignore imports with a dummy span
+ // because this means that they were generated in some fashion by the
+ // compiler and we don't need to consider them.
+ ast::ItemKind::Use(..) if item.vis.kind.is_pub() || item.span.is_dummy() => return,
+ ast::ItemKind::ExternCrate(orig_name) => {
+ self.extern_crate_items.push(ExternCrateToLint {
+ id: item.id,
+ span: item.span,
+ vis_span: item.vis.span,
+ span_with_attributes: item.span_with_attributes(),
+ has_attrs: !item.attrs.is_empty(),
+ ident: item.ident,
+ renames: orig_name.is_some(),
+ });
}
+ _ => {}
}
+ self.item_span = item.span_with_attributes();
visit::walk_item(self, item);
}
@@ -222,8 +249,11 @@ fn calc_unused_spans(
}
}
-impl Resolver<'_> {
+impl Resolver<'_, '_> {
pub(crate) fn check_unused(&mut self, krate: &ast::Crate) {
+ let tcx = self.tcx;
+ let mut maybe_unused_extern_crates = FxHashMap::default();
+
for import in self.potentially_unused_imports.iter() {
match import.kind {
_ if import.used.get()
@@ -246,7 +276,14 @@ impl Resolver<'_> {
}
ImportKind::ExternCrate { id, .. } => {
let def_id = self.local_def_id(id);
- self.maybe_unused_extern_crates.push((def_id, import.span));
+ if self.extern_crate_map.get(&def_id).map_or(true, |&cnum| {
+ !tcx.is_compiler_builtins(cnum)
+ && !tcx.is_panic_runtime(cnum)
+ && !tcx.has_global_allocator(cnum)
+ && !tcx.has_panic_handler(cnum)
+ }) {
+ maybe_unused_extern_crates.insert(id, import.span);
+ }
}
ImportKind::MacroUse => {
let msg = "unused `#[macro_use]` import";
@@ -259,6 +296,7 @@ impl Resolver<'_> {
let mut visitor = UnusedImportCheckVisitor {
r: self,
unused_imports: Default::default(),
+ extern_crate_items: Default::default(),
base_use_tree: None,
base_id: ast::DUMMY_NODE_ID,
item_span: DUMMY_SP,
@@ -290,7 +328,7 @@ impl Resolver<'_> {
let ms = MultiSpan::from_spans(spans.clone());
let mut span_snippets = spans
.iter()
- .filter_map(|s| match visitor.r.session.source_map().span_to_snippet(*s) {
+ .filter_map(|s| match tcx.sess.source_map().span_to_snippet(*s) {
Ok(s) => Some(format!("`{}`", s)),
_ => None,
})
@@ -317,7 +355,7 @@ impl Resolver<'_> {
// If we are in the `--test` mode, suppress a help that adds the `#[cfg(test)]`
// attribute; however, if not, suggest adding the attribute. There is no way to
// retrieve attributes here because we do not have a `TyCtxt` yet.
- let test_module_span = if visitor.r.session.opts.test {
+ let test_module_span = if tcx.sess.opts.test {
None
} else {
let parent_module = visitor.r.get_nearest_non_block_module(
@@ -346,5 +384,74 @@ impl Resolver<'_> {
BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes, test_module_span),
);
}
+
+ for extern_crate in visitor.extern_crate_items {
+ let warn_if_unused = !extern_crate.ident.name.as_str().starts_with('_');
+
+ // If the crate is fully unused, we suggest removing it altogether.
+ // We do this in any edition.
+ if warn_if_unused {
+ if let Some(&span) = maybe_unused_extern_crates.get(&extern_crate.id) {
+ visitor.r.lint_buffer.buffer_lint_with_diagnostic(
+ UNUSED_EXTERN_CRATES,
+ extern_crate.id,
+ span,
+ "unused extern crate",
+ BuiltinLintDiagnostics::UnusedExternCrate {
+ removal_span: extern_crate.span_with_attributes,
+ },
+ );
+ continue;
+ }
+ }
+
+ // If we are not in Rust 2018 edition, then we don't make any further
+ // suggestions.
+ if !tcx.sess.rust_2018() {
+ continue;
+ }
+
+ // If the extern crate has any attributes, they may have funky
+ // semantics we can't faithfully represent using `use` (most
+ // notably `#[macro_use]`). Ignore it.
+ if extern_crate.has_attrs {
+ continue;
+ }
+
+ // If the extern crate is renamed, then we cannot suggest replacing it with a use as this
+ // would not insert the new name into the prelude, where other imports in the crate may be
+ // expecting it.
+ if extern_crate.renames {
+ continue;
+ }
+
+ // If the extern crate isn't in the extern prelude,
+ // there is no way it can be written as a `use`.
+ if !visitor
+ .r
+ .extern_prelude
+ .get(&extern_crate.ident)
+ .map_or(false, |entry| !entry.introduced_by_item)
+ {
+ continue;
+ }
+
+ let vis_span = extern_crate
+ .vis_span
+ .find_ancestor_inside(extern_crate.span)
+ .unwrap_or(extern_crate.vis_span);
+ let ident_span = extern_crate
+ .ident
+ .span
+ .find_ancestor_inside(extern_crate.span)
+ .unwrap_or(extern_crate.ident.span);
+ visitor.r.lint_buffer.buffer_lint_with_diagnostic(
+ UNUSED_EXTERN_CRATES,
+ extern_crate.id,
+ extern_crate.span,
+ "`extern crate` is not idiomatic in the new edition",
+ BuiltinLintDiagnostics::ExternCrateNotIdiomatic { vis_span, ident_span },
+ );
+ }
}
}
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 2764a6c28..e7ff236f8 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -9,7 +9,7 @@ use rustc_span::symbol::sym;
use rustc_span::Span;
pub(crate) fn collect_definitions(
- resolver: &mut Resolver<'_>,
+ resolver: &mut Resolver<'_, '_>,
fragment: &AstFragment,
expansion: LocalExpnId,
) {
@@ -18,14 +18,14 @@ pub(crate) fn collect_definitions(
}
/// Creates `DefId`s for nodes in the AST.
-struct DefCollector<'a, 'b> {
- resolver: &'a mut Resolver<'b>,
+struct DefCollector<'a, 'b, 'tcx> {
+ resolver: &'a mut Resolver<'b, 'tcx>,
parent_def: LocalDefId,
impl_trait_context: ImplTraitContext,
expansion: LocalExpnId,
}
-impl<'a, 'b> DefCollector<'a, 'b> {
+impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> {
fn create_def(&mut self, node_id: NodeId, data: DefPathData, span: Span) -> LocalDefId {
let parent_def = self.parent_def;
debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
@@ -81,7 +81,7 @@ impl<'a, 'b> DefCollector<'a, 'b> {
}
}
-impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
+impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
fn visit_item(&mut self, i: &'a Item) {
debug!("visit_item: {:?}", i);
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 366086152..7add59ac6 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -12,25 +12,24 @@ use rustc_errors::{struct_span_err, SuggestionStyle};
use rustc_feature::BUILTIN_ATTRIBUTES;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::PrimTy;
-use rustc_index::vec::IndexVec;
use rustc_middle::bug;
-use rustc_middle::ty::DefIdTree;
+use rustc_middle::ty::{DefIdTree, TyCtxt};
use rustc_session::lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE;
use rustc_session::lint::builtin::MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS;
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::Session;
+use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::edition::Edition;
use rustc_span::hygiene::MacroKind;
-use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, Span, SyntaxContext};
use thin_vec::ThinVec;
use crate::errors as errs;
-use crate::imports::{Import, ImportKind, ImportResolver};
+use crate::imports::{Import, ImportKind};
use crate::late::{PatternSource, Rib};
use crate::path_names_to_string;
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, Finalize};
@@ -114,7 +113,7 @@ fn reduce_impl_span_to_impl_keyword(sm: &SourceMap, impl_span: Span) -> Span {
sm.span_until_whitespace(impl_span)
}
-impl<'a> Resolver<'a> {
+impl<'a, 'tcx> Resolver<'a, 'tcx> {
pub(crate) fn report_errors(&mut self, krate: &Crate) {
self.report_with_use_injections(krate);
@@ -154,8 +153,7 @@ impl<'a> Resolver<'a> {
if !candidates.is_empty() {
show_candidates(
- &self.session,
- &self.untracked.source_span,
+ self.tcx,
&mut err,
span,
&candidates,
@@ -191,6 +189,8 @@ impl<'a> Resolver<'a> {
}
let container = match parent.kind {
+ // Avoid using TyCtxt::def_kind_descr in the resolver, because it
+ // indirectly *calls* the resolver, and would cause a query cycle.
ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()),
ModuleKind::Block => "block",
};
@@ -206,7 +206,7 @@ impl<'a> Resolver<'a> {
};
let (name, span) =
- (ident.name, self.session.source_map().guess_head_span(new_binding.span));
+ (ident.name, self.tcx.sess.source_map().guess_head_span(new_binding.span));
if let Some(s) = self.name_already_seen.get(&name) {
if s == &span {
@@ -226,15 +226,15 @@ impl<'a> Resolver<'a> {
let msg = format!("the name `{}` is defined multiple times", name);
let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
- (true, true) => struct_span_err!(self.session, span, E0259, "{}", msg),
+ (true, true) => struct_span_err!(self.tcx.sess, span, E0259, "{}", msg),
(true, _) | (_, true) => match new_binding.is_import() && old_binding.is_import() {
- true => struct_span_err!(self.session, span, E0254, "{}", msg),
- false => struct_span_err!(self.session, span, E0260, "{}", msg),
+ true => struct_span_err!(self.tcx.sess, span, E0254, "{}", msg),
+ false => struct_span_err!(self.tcx.sess, span, E0260, "{}", msg),
},
_ => match (old_binding.is_import_user_facing(), new_binding.is_import_user_facing()) {
- (false, false) => struct_span_err!(self.session, span, E0428, "{}", msg),
- (true, true) => struct_span_err!(self.session, span, E0252, "{}", msg),
- _ => struct_span_err!(self.session, span, E0255, "{}", msg),
+ (false, false) => struct_span_err!(self.tcx.sess, span, E0428, "{}", msg),
+ (true, true) => struct_span_err!(self.tcx.sess, span, E0252, "{}", msg),
+ _ => struct_span_err!(self.tcx.sess, span, E0255, "{}", msg),
},
};
@@ -248,7 +248,7 @@ impl<'a> Resolver<'a> {
err.span_label(span, format!("`{}` re{} here", name, new_participle));
if !old_binding.span.is_dummy() && old_binding.span != span {
err.span_label(
- self.session.source_map().guess_head_span(old_binding.span),
+ self.tcx.sess.source_map().guess_head_span(old_binding.span),
format!("previous {} of the {} `{}` here", old_noun, old_kind, name),
);
}
@@ -352,7 +352,7 @@ impl<'a> Resolver<'a> {
if let Some(pos) =
source.span.hi().0.checked_sub(binding_span.lo().0).map(|pos| pos as usize)
{
- if let Ok(snippet) = self.session.source_map().span_to_snippet(binding_span) {
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span) {
if pos <= snippet.len() {
suggestion = Some(format!(
"{} as {}{}",
@@ -426,12 +426,12 @@ impl<'a> Resolver<'a> {
// `a` and `import.use_span` is `issue_52891::{d, e, a};`.
let (found_closing_brace, span) =
- find_span_of_binding_until_next_binding(self.session, binding_span, import.use_span);
+ find_span_of_binding_until_next_binding(self.tcx.sess, binding_span, import.use_span);
// If there was a closing brace then identify the span to remove any trailing commas from
// previous imports.
if found_closing_brace {
- if let Some(span) = extend_span_to_previous_binding(self.session, span) {
+ if let Some(span) = extend_span_to_previous_binding(self.tcx.sess, span) {
err.tool_only_span_suggestion(span, message, "", Applicability::MaybeIncorrect);
} else {
// Remove the entire line if we cannot extend the span back, this indicates an
@@ -462,7 +462,9 @@ impl<'a> Resolver<'a> {
let first_name = match path.get(0) {
// In the 2018 edition this lint is a hard error, so nothing to do
- Some(seg) if seg.ident.span.rust_2015() && self.session.rust_2015() => seg.ident.name,
+ Some(seg) if seg.ident.span.is_rust_2015() && self.tcx.sess.is_rust_2015() => {
+ seg.ident.name
+ }
_ => return,
};
@@ -539,14 +541,14 @@ impl<'a> Resolver<'a> {
match resolution_error {
ResolutionError::GenericParamsFromOuterFunction(outer_res, has_generic_params) => {
let mut err = struct_span_err!(
- self.session,
+ self.tcx.sess,
span,
E0401,
"can't use generic parameters from outer function",
);
err.span_label(span, "use of generic parameter from outer function");
- let sm = self.session.source_map();
+ let sm = self.tcx.sess.source_map();
let def_id = match outer_res {
Res::SelfTyParam { .. } => {
err.span_label(span, "can't use `Self` here");
@@ -603,10 +605,11 @@ impl<'a> Resolver<'a> {
err
}
ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => self
- .session
+ .tcx
+ .sess
.create_err(errs::NameAlreadyUsedInParameterList { span, first_use_span, name }),
ResolutionError::MethodNotMemberOfTrait(method, trait_, candidate) => {
- self.session.create_err(errs::MethodNotMemberOfTrait {
+ self.tcx.sess.create_err(errs::MethodNotMemberOfTrait {
span,
method,
trait_,
@@ -617,7 +620,7 @@ impl<'a> Resolver<'a> {
})
}
ResolutionError::TypeNotMemberOfTrait(type_, trait_, candidate) => {
- self.session.create_err(errs::TypeNotMemberOfTrait {
+ self.tcx.sess.create_err(errs::TypeNotMemberOfTrait {
span,
type_,
trait_,
@@ -628,7 +631,7 @@ impl<'a> Resolver<'a> {
})
}
ResolutionError::ConstNotMemberOfTrait(const_, trait_, candidate) => {
- self.session.create_err(errs::ConstNotMemberOfTrait {
+ self.tcx.sess.create_err(errs::ConstNotMemberOfTrait {
span,
const_,
trait_,
@@ -646,7 +649,7 @@ impl<'a> Resolver<'a> {
let msp = MultiSpan::from_spans(target_sp.clone());
let mut err = struct_span_err!(
- self.session,
+ self.tcx.sess,
msp,
E0408,
"variable `{}` is not bound in all patterns",
@@ -684,8 +687,7 @@ impl<'a> Resolver<'a> {
err.span_help(span, &help_msg);
}
show_candidates(
- &self.session,
- &self.untracked.source_span,
+ self.tcx,
&mut err,
Some(span),
&import_suggestions,
@@ -699,17 +701,19 @@ impl<'a> Resolver<'a> {
err
}
ResolutionError::VariableBoundWithDifferentMode(variable_name, first_binding_span) => {
- self.session.create_err(errs::VariableBoundWithDifferentMode {
+ self.tcx.sess.create_err(errs::VariableBoundWithDifferentMode {
span,
first_binding_span,
variable_name,
})
}
ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => self
- .session
+ .tcx
+ .sess
.create_err(errs::IdentifierBoundMoreThanOnceInParameterList { span, identifier }),
ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => self
- .session
+ .tcx
+ .sess
.create_err(errs::IdentifierBoundMoreThanOnceInSamePattern { span, identifier }),
ResolutionError::UndeclaredLabel { name, suggestion } => {
let ((sub_reachable, sub_reachable_suggestion), sub_unreachable) = match suggestion
@@ -735,7 +739,7 @@ impl<'a> Resolver<'a> {
// No similarly-named labels exist.
None => ((None, None), None),
};
- self.session.create_err(errs::UndeclaredLabel {
+ self.tcx.sess.create_err(errs::UndeclaredLabel {
span,
name,
sub_reachable,
@@ -760,21 +764,22 @@ impl<'a> Resolver<'a> {
};
(Some(suggestion), Some(mpart_suggestion))
};
- self.session.create_err(errs::SelfImportsOnlyAllowedWithin {
+ self.tcx.sess.create_err(errs::SelfImportsOnlyAllowedWithin {
span,
suggestion,
mpart_suggestion,
})
}
ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
- self.session.create_err(errs::SelfImportCanOnlyAppearOnceInTheList { span })
- }
- ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
- self.session.create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span })
+ self.tcx.sess.create_err(errs::SelfImportCanOnlyAppearOnceInTheList { span })
}
+ ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => self
+ .tcx
+ .sess
+ .create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span }),
ResolutionError::FailedToResolve { label, suggestion } => {
let mut err =
- struct_span_err!(self.session, span, E0433, "failed to resolve: {}", &label);
+ struct_span_err!(self.tcx.sess, span, E0433, "failed to resolve: {}", &label);
err.span_label(span, label);
if let Some((suggestions, msg, applicability)) = suggestion {
@@ -788,7 +793,7 @@ impl<'a> Resolver<'a> {
err
}
ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
- self.session.create_err(errs::CannotCaptureDynamicEnvironmentInFnItem { span })
+ self.tcx.sess.create_err(errs::CannotCaptureDynamicEnvironmentInFnItem { span })
}
ResolutionError::AttemptToUseNonConstantValueInConstant(ident, suggestion, current) => {
// let foo =...
@@ -800,12 +805,13 @@ impl<'a> Resolver<'a> {
// the further the two are apart, the higher the chance of the suggestion being wrong
let sp = self
- .session
+ .tcx
+ .sess
.source_map()
.span_extend_to_prev_str(ident.span, current, true, false);
let ((with, with_label), without) = match sp {
- Some(sp) if !self.session.source_map().is_multiline(sp) => {
+ Some(sp) if !self.tcx.sess.source_map().is_multiline(sp) => {
let sp = sp.with_lo(BytePos(sp.lo().0 - (current.len() as u32)));
(
(Some(errs::AttemptToUseNonConstantValueInConstantWithSuggestion {
@@ -826,7 +832,7 @@ impl<'a> Resolver<'a> {
),
};
- self.session.create_err(errs::AttemptToUseNonConstantValueInConstant {
+ self.tcx.sess.create_err(errs::AttemptToUseNonConstantValueInConstant {
span,
with,
with_label,
@@ -840,7 +846,7 @@ impl<'a> Resolver<'a> {
article,
shadowed_binding,
shadowed_binding_span,
- } => self.session.create_err(errs::BindingShadowsSomethingUnacceptable {
+ } => self.tcx.sess.create_err(errs::BindingShadowsSomethingUnacceptable {
span,
shadowing_binding,
shadowed_binding,
@@ -857,13 +863,13 @@ impl<'a> Resolver<'a> {
name,
}),
ResolutionError::ForwardDeclaredGenericParam => {
- self.session.create_err(errs::ForwardDeclaredGenericParam { span })
+ self.tcx.sess.create_err(errs::ForwardDeclaredGenericParam { span })
}
ResolutionError::ParamInTyOfConstParam(name) => {
- self.session.create_err(errs::ParamInTyOfConstParam { span, name })
+ self.tcx.sess.create_err(errs::ParamInTyOfConstParam { span, name })
}
ResolutionError::ParamInNonTrivialAnonConst { name, is_type } => {
- self.session.create_err(errs::ParamInNonTrivialAnonConst {
+ self.tcx.sess.create_err(errs::ParamInNonTrivialAnonConst {
span,
name,
sub_is_type: if is_type {
@@ -872,13 +878,14 @@ impl<'a> Resolver<'a> {
errs::ParamInNonTrivialAnonConstIsType::NotAType { name }
},
help: self
- .session
+ .tcx
+ .sess
.is_nightly_build()
.then_some(errs::ParamInNonTrivialAnonConstHelp),
})
}
ResolutionError::SelfInGenericParamDefault => {
- self.session.create_err(errs::SelfInGenericParamDefault { span })
+ self.tcx.sess.create_err(errs::SelfInGenericParamDefault { span })
}
ResolutionError::UnreachableLabel { name, definition_span, suggestion } => {
let ((sub_suggestion_label, sub_suggestion), sub_unreachable_label) =
@@ -906,7 +913,7 @@ impl<'a> Resolver<'a> {
// No similarly-named labels exist.
None => ((None, None), None),
};
- self.session.create_err(errs::UnreachableLabel {
+ self.tcx.sess.create_err(errs::UnreachableLabel {
span,
name,
definition_span,
@@ -922,7 +929,7 @@ impl<'a> Resolver<'a> {
trait_item_span,
trait_path,
} => {
- let mut err = self.session.struct_span_err_with_code(
+ let mut err = self.tcx.sess.struct_span_err_with_code(
span,
&format!(
"item `{}` is an associated {}, which doesn't match its trait `{}`",
@@ -935,9 +942,12 @@ impl<'a> Resolver<'a> {
err
}
ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => self
- .session
+ .tcx
+ .sess
.create_err(errs::TraitImplDuplicate { span, name, trait_item_span, old_span }),
- ResolutionError::InvalidAsmSym => self.session.create_err(errs::InvalidAsmSym { span }),
+ ResolutionError::InvalidAsmSym => {
+ self.tcx.sess.create_err(errs::InvalidAsmSym { span })
+ }
}
}
@@ -947,7 +957,7 @@ impl<'a> Resolver<'a> {
) -> ErrorGuaranteed {
match vis_resolution_error {
VisResolutionError::Relative2018(span, path) => {
- self.session.create_err(errs::Relative2018 {
+ self.tcx.sess.create_err(errs::Relative2018 {
span,
path_span: path.span,
// intentionally converting to String, as the text would also be used as
@@ -956,18 +966,20 @@ impl<'a> Resolver<'a> {
})
}
VisResolutionError::AncestorOnly(span) => {
- self.session.create_err(errs::AncestorOnly(span))
+ self.tcx.sess.create_err(errs::AncestorOnly(span))
}
VisResolutionError::FailedToResolve(span, label, suggestion) => {
self.into_struct_error(span, ResolutionError::FailedToResolve { label, suggestion })
}
VisResolutionError::ExpectedFound(span, path_str, res) => {
- self.session.create_err(errs::ExpectedFound { span, res, path_str })
+ self.tcx.sess.create_err(errs::ExpectedFound { span, res, path_str })
}
VisResolutionError::Indeterminate(span) => {
- self.session.create_err(errs::Indeterminate(span))
+ self.tcx.sess.create_err(errs::Indeterminate(span))
+ }
+ VisResolutionError::ModuleOnly(span) => {
+ self.tcx.sess.create_err(errs::ModuleOnly(span))
}
- VisResolutionError::ModuleOnly(span) => self.session.create_err(errs::ModuleOnly(span)),
}
.emit()
}
@@ -1204,7 +1216,7 @@ impl<'a> Resolver<'a> {
// a note about editions
let note = if let Some(did) = did {
let requires_note = !did.is_local()
- && this.cstore().item_attrs_untracked(did, this.session).any(
+ && this.cstore().item_attrs_untracked(did, this.tcx.sess).any(
|attr| {
if attr.has_name(sym::rustc_diagnostic_item) {
[sym::TryInto, sym::TryFrom, sym::FromIterator]
@@ -1302,7 +1314,7 @@ impl<'a> Resolver<'a> {
// otherwise cause duplicate suggestions.
continue;
}
- let crate_id = self.crate_loader().maybe_process_path_extern(ident.name);
+ let crate_id = self.crate_loader(|c| c.maybe_process_path_extern(ident.name));
if let Some(crate_id) = crate_id {
let crate_root = self.expect_module(crate_id.as_def_id());
suggestions.extend(self.lookup_import_candidates_from_module(
@@ -1339,8 +1351,7 @@ impl<'a> Resolver<'a> {
let import_suggestions =
self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected);
show_candidates(
- &self.session,
- &self.untracked.source_span,
+ self.tcx,
err,
None,
&import_suggestions,
@@ -1364,7 +1375,7 @@ impl<'a> Resolver<'a> {
&& let ModuleKind::Def(DefKind::Enum, def_id, _) = parent_scope.module.kind
&& let Some(span) = self.opt_span(def_id)
{
- let source_map = self.session.source_map();
+ let source_map = self.tcx.sess.source_map();
let head_span = source_map.guess_head_span(span);
if let Ok(head) = source_map.span_to_snippet(head_span) {
err.span_suggestion(head_span, "consider adding a derive", format!("#[derive(Default)]\n{head}"), Applicability::MaybeIncorrect);
@@ -1441,7 +1452,7 @@ impl<'a> Resolver<'a> {
};
let def_span = suggestion.res.opt_def_id().and_then(|def_id| match def_id.krate {
LOCAL_CRATE => self.opt_span(def_id),
- _ => Some(self.cstore().get_span_untracked(def_id, self.session)),
+ _ => Some(self.cstore().get_span_untracked(def_id, self.tcx.sess)),
});
if let Some(def_span) = def_span {
if span.overlaps(def_span) {
@@ -1471,7 +1482,7 @@ impl<'a> Resolver<'a> {
};
err.span_label(
- self.session.source_map().guess_head_span(def_span),
+ self.tcx.sess.source_map().guess_head_span(def_span),
&format!(
"{}{} `{}` defined here",
prefix,
@@ -1496,7 +1507,7 @@ impl<'a> Resolver<'a> {
fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: bool) -> String {
let res = b.res();
- if b.span.is_dummy() || !self.session.source_map().is_span_accessible(b.span) {
+ if b.span.is_dummy() || !self.tcx.sess.source_map().is_span_accessible(b.span) {
// These already contain the "built-in" prefix or look bad with it.
let add_built_in =
!matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod);
@@ -1504,7 +1515,7 @@ impl<'a> Resolver<'a> {
("", " from prelude")
} else if b.is_extern_crate()
&& !b.is_import()
- && self.session.opts.externs.get(ident.as_str()).is_some()
+ && self.tcx.sess.opts.externs.get(ident.as_str()).is_some()
{
("", " passed with `--extern`")
} else if add_built_in {
@@ -1530,7 +1541,7 @@ impl<'a> Resolver<'a> {
(b1, b2, misc1, misc2, false)
};
- let mut err = struct_span_err!(self.session, ident.span, E0659, "`{ident}` is ambiguous");
+ let mut err = struct_span_err!(self.tcx.sess, ident.span, E0659, "`{ident}` is ambiguous");
err.span_label(ident.span, "ambiguous name");
err.note(&format!("ambiguous because of {}", kind.descr()));
@@ -1552,12 +1563,12 @@ impl<'a> Resolver<'a> {
if b.is_extern_crate() && ident.span.rust_2018() {
help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously"))
}
- if misc == AmbiguityErrorMisc::SuggestCrate {
- help_msgs
- .push(format!("use `crate::{ident}` to refer to this {thing} unambiguously"))
- } else if misc == AmbiguityErrorMisc::SuggestSelf {
- help_msgs
- .push(format!("use `self::{ident}` to refer to this {thing} unambiguously"))
+ match misc {
+ AmbiguityErrorMisc::SuggestCrate => help_msgs
+ .push(format!("use `crate::{ident}` to refer to this {thing} unambiguously")),
+ AmbiguityErrorMisc::SuggestSelf => help_msgs
+ .push(format!("use `self::{ident}` to refer to this {thing} unambiguously")),
+ AmbiguityErrorMisc::FromPrelude | AmbiguityErrorMisc::None => {}
}
err.span_note(b.span, &note_msg);
@@ -1602,7 +1613,7 @@ impl<'a> Resolver<'a> {
// Print the primary message.
let descr = get_descr(binding);
let mut err =
- struct_span_err!(self.session, ident.span, E0603, "{} `{}` is private", descr, ident);
+ struct_span_err!(self.tcx.sess, ident.span, E0603, "{} `{}` is private", descr, ident);
err.span_label(ident.span, &format!("private {}", descr));
if let Some(span) = ctor_fields_span {
err.span_label(span, "a constructor is private if any of the fields is private");
@@ -1648,7 +1659,7 @@ impl<'a> Resolver<'a> {
which = if first { "" } else { " which" },
dots = if next_binding.is_some() { "..." } else { "" },
);
- let def_span = self.session.source_map().guess_head_span(binding.span);
+ let def_span = self.tcx.sess.source_map().guess_head_span(binding.span);
let mut note_span = MultiSpan::from_span(def_span);
if !first && binding.vis.is_public() {
note_span.push_span_label(def_span, "consider importing it directly");
@@ -1717,7 +1728,7 @@ impl<'a> Resolver<'a> {
Applicability::MaybeIncorrect,
)),
)
- } else if self.session.edition() == Edition::Edition2015 {
+ } else if self.tcx.sess.is_rust_2015() {
(
format!("maybe a missing crate `{ident}`?"),
Some((
@@ -1736,7 +1747,7 @@ impl<'a> Resolver<'a> {
let parent = match parent {
// ::foo is mounted at the crate root for 2015, and is the extern
// prelude for 2018+
- kw::PathRoot if self.session.edition() > Edition::Edition2015 => {
+ kw::PathRoot if self.tcx.sess.edition() > Edition::Edition2015 => {
"the list of imported crates".to_owned()
}
kw::PathRoot | kw::Crate => "the crate root".to_owned(),
@@ -1795,6 +1806,8 @@ impl<'a> Resolver<'a> {
found("module")
} else {
match binding.res() {
+ // Avoid using TyCtxt::def_kind_descr in the resolver, because it
+ // indirectly *calls* the resolver, and would cause a query cycle.
Res::Def(kind, id) => found(kind.descr(id)),
_ => found(ns_to_try.descr()),
}
@@ -1879,15 +1892,13 @@ impl<'a> Resolver<'a> {
(format!("use of undeclared crate or module `{}`", ident), suggestion)
}
}
-}
-impl<'a, 'b> ImportResolver<'a, 'b> {
/// Adds suggestions for a path that cannot be resolved.
pub(crate) fn make_path_suggestion(
&mut self,
span: Span,
mut path: Vec<Segment>,
- parent_scope: &ParentScope<'b>,
+ parent_scope: &ParentScope<'a>,
) -> Option<(Vec<Segment>, Option<String>)> {
debug!("make_path_suggestion: span={:?} path={:?}", span, path);
@@ -1922,11 +1933,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
fn make_missing_self_suggestion(
&mut self,
mut path: Vec<Segment>,
- parent_scope: &ParentScope<'b>,
+ parent_scope: &ParentScope<'a>,
) -> Option<(Vec<Segment>, Option<String>)> {
// Replace first ident with `self` and check if that is valid.
path[0].ident.name = kw::SelfLower;
- let result = self.r.maybe_resolve_path(&path, None, parent_scope);
+ let result = self.maybe_resolve_path(&path, None, parent_scope);
debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
if let PathResult::Module(..) = result { Some((path, None)) } else { None }
}
@@ -1941,11 +1952,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
fn make_missing_crate_suggestion(
&mut self,
mut path: Vec<Segment>,
- parent_scope: &ParentScope<'b>,
+ parent_scope: &ParentScope<'a>,
) -> Option<(Vec<Segment>, Option<String>)> {
// Replace first ident with `crate` and check if that is valid.
path[0].ident.name = kw::Crate;
- let result = self.r.maybe_resolve_path(&path, None, parent_scope);
+ let result = self.maybe_resolve_path(&path, None, parent_scope);
debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result);
if let PathResult::Module(..) = result {
Some((
@@ -1972,11 +1983,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
fn make_missing_super_suggestion(
&mut self,
mut path: Vec<Segment>,
- parent_scope: &ParentScope<'b>,
+ parent_scope: &ParentScope<'a>,
) -> Option<(Vec<Segment>, Option<String>)> {
// Replace first ident with `crate` and check if that is valid.
path[0].ident.name = kw::Super;
- let result = self.r.maybe_resolve_path(&path, None, parent_scope);
+ let result = self.maybe_resolve_path(&path, None, parent_scope);
debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result);
if let PathResult::Module(..) = result { Some((path, None)) } else { None }
}
@@ -1994,9 +2005,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
fn make_external_crate_suggestion(
&mut self,
mut path: Vec<Segment>,
- parent_scope: &ParentScope<'b>,
+ parent_scope: &ParentScope<'a>,
) -> Option<(Vec<Segment>, Option<String>)> {
- if path[1].ident.span.rust_2015() {
+ if path[1].ident.span.is_rust_2015() {
return None;
}
@@ -2004,13 +2015,13 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
// 1) some consistent ordering for emitted diagnostics, and
// 2) `std` suggestions before `core` suggestions.
let mut extern_crate_names =
- self.r.extern_prelude.iter().map(|(ident, _)| ident.name).collect::<Vec<_>>();
+ self.extern_prelude.iter().map(|(ident, _)| ident.name).collect::<Vec<_>>();
extern_crate_names.sort_by(|a, b| b.as_str().partial_cmp(a.as_str()).unwrap());
for name in extern_crate_names.into_iter() {
// Replace first ident with a crate name and check if that is valid.
path[0].ident.name = name;
- let result = self.r.maybe_resolve_path(&path, None, parent_scope);
+ let result = self.maybe_resolve_path(&path, None, parent_scope);
debug!(
"make_external_crate_suggestion: name={:?} path={:?} result={:?}",
name, path, result
@@ -2037,8 +2048,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
/// ```
pub(crate) fn check_for_module_export_macro(
&mut self,
- import: &'b Import<'b>,
- module: ModuleOrUniformRoot<'b>,
+ import: &'a Import<'a>,
+ module: ModuleOrUniformRoot<'a>,
ident: Ident,
) -> Option<(Option<Suggestion>, Option<String>)> {
let ModuleOrUniformRoot::Module(mut crate_module) = module else {
@@ -2055,8 +2066,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
return None;
}
- let resolutions = self.r.resolutions(crate_module).borrow();
- let resolution = resolutions.get(&self.r.new_key(ident, MacroNS))?;
+ let resolutions = self.resolutions(crate_module).borrow();
+ let resolution = resolutions.get(&self.new_key(ident, MacroNS))?;
let binding = resolution.borrow().binding()?;
if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() {
let module_name = crate_module.kind.name().unwrap();
@@ -2077,7 +2088,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
// ie. `use a::b::{c, d, e};`
// ^^^
let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding(
- self.r.session,
+ self.tcx.sess,
import.span,
import.use_span,
);
@@ -2096,7 +2107,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
// ie. `use a::b::{c, d};`
// ^^^
if let Some(previous_span) =
- extend_span_to_previous_binding(self.r.session, binding_span)
+ extend_span_to_previous_binding(self.tcx.sess, binding_span)
{
debug!("check_for_module_export_macro: previous_span={:?}", previous_span);
removal_span = removal_span.with_lo(previous_span.lo());
@@ -2114,7 +2125,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
// or `use a::{b, c, d}};`
// ^^^^^^^^^^^
let (has_nested, after_crate_name) = find_span_immediately_after_crate_name(
- self.r.session,
+ self.tcx.sess,
module_name,
import.use_span,
);
@@ -2123,7 +2134,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
has_nested, after_crate_name
);
- let source_map = self.r.session.source_map();
+ let source_map = self.tcx.sess.source_map();
// Make sure this is actually crate-relative.
let is_definitely_crate = import
@@ -2345,8 +2356,7 @@ pub(crate) enum DiagnosticMode {
}
pub(crate) fn import_candidates(
- session: &Session,
- source_span: &IndexVec<LocalDefId, Span>,
+ tcx: TyCtxt<'_>,
err: &mut Diagnostic,
// This is `None` if all placement locations are inside expansions
use_placement_span: Option<Span>,
@@ -2355,8 +2365,7 @@ pub(crate) fn import_candidates(
append: &str,
) {
show_candidates(
- session,
- source_span,
+ tcx,
err,
use_placement_span,
candidates,
@@ -2372,8 +2381,7 @@ pub(crate) fn import_candidates(
/// entities with that name in all crates. This method allows outputting the
/// results of this search in a programmer-friendly way
fn show_candidates(
- session: &Session,
- source_span: &IndexVec<LocalDefId, Span>,
+ tcx: TyCtxt<'_>,
err: &mut Diagnostic,
// This is `None` if all placement locations are inside expansions
use_placement_span: Option<Span>,
@@ -2498,8 +2506,8 @@ fn show_candidates(
);
if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
- let span = source_span[local_def_id];
- let span = session.source_map().guess_head_span(span);
+ let span = tcx.source_span(local_def_id);
+ let span = tcx.sess.source_map().guess_head_span(span);
let mut multi_span = MultiSpan::from_span(span);
multi_span.push_span_label(span, "not accessible");
err.span_note(multi_span, &msg);
@@ -2529,8 +2537,8 @@ fn show_candidates(
let mut spans = Vec::new();
for (name, _, def_id, _) in &inaccessible_path_strings {
if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
- let span = source_span[local_def_id];
- let span = session.source_map().guess_head_span(span);
+ let span = tcx.source_span(local_def_id);
+ let span = tcx.sess.source_map().guess_head_span(span);
spans.push((name, span));
} else {
if !has_colon {
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index b8efa3f8b..7bd90d7e3 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -1,4 +1,4 @@
-use crate::{NameBinding, NameBindingKind, Resolver, ResolverTree};
+use crate::{NameBinding, NameBindingKind, Resolver};
use rustc_ast::ast;
use rustc_ast::visit;
use rustc_ast::visit::Visitor;
@@ -7,8 +7,8 @@ use rustc_ast::EnumDef;
use rustc_data_structures::intern::Interned;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::def_id::CRATE_DEF_ID;
+use rustc_middle::middle::privacy::Level;
use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility};
-use rustc_middle::middle::privacy::{IntoDefIdTree, Level};
use rustc_middle::ty::{DefIdTree, Visibility};
use std::mem;
@@ -29,8 +29,8 @@ impl ParentId<'_> {
}
}
-pub struct EffectiveVisibilitiesVisitor<'r, 'a> {
- r: &'r mut Resolver<'a>,
+pub(crate) struct EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
+ r: &'r mut Resolver<'a, 'tcx>,
def_effective_visibilities: EffectiveVisibilities,
/// While walking import chains we need to track effective visibilities per-binding, and def id
/// keys in `Resolver::effective_visibilities` are not enough for that, because multiple
@@ -41,7 +41,7 @@ pub struct EffectiveVisibilitiesVisitor<'r, 'a> {
changed: bool,
}
-impl Resolver<'_> {
+impl Resolver<'_, '_> {
fn nearest_normal_mod(&mut self, def_id: LocalDefId) -> LocalDefId {
self.get_nearest_non_block_module(def_id.to_def_id()).nearest_parent_mod().expect_local()
}
@@ -67,18 +67,14 @@ impl Resolver<'_> {
}
}
-impl<'a, 'b> IntoDefIdTree for &'b mut Resolver<'a> {
- type Tree = &'b Resolver<'a>;
- fn tree(self) -> Self::Tree {
- self
- }
-}
-
-impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
+impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
/// Fills the `Resolver::effective_visibilities` table with public & exported items
/// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
/// need access to a TyCtxt for that.
- pub fn compute_effective_visibilities<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
+ pub(crate) fn compute_effective_visibilities<'c>(
+ r: &'r mut Resolver<'a, 'tcx>,
+ krate: &'c Crate,
+ ) {
let mut visitor = EffectiveVisibilitiesVisitor {
r,
def_effective_visibilities: Default::default(),
@@ -104,11 +100,7 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
for (binding, eff_vis) in visitor.import_effective_visibilities.iter() {
let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
if let Some(node_id) = import.id() {
- r.effective_visibilities.update_eff_vis(
- r.local_def_id(node_id),
- eff_vis,
- ResolverTree(&r.untracked),
- )
+ r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx)
}
}
@@ -164,26 +156,28 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
let nominal_vis = binding.vis.expect_local();
let private_vis = self.cheap_private_vis(parent_id);
let inherited_eff_vis = self.effective_vis_or_private(parent_id);
+ let tcx = self.r.tcx;
self.changed |= self.import_effective_visibilities.update(
binding,
nominal_vis,
- |r| (private_vis.unwrap_or_else(|| r.private_vis_import(binding)), r),
+ || private_vis.unwrap_or_else(|| self.r.private_vis_import(binding)),
inherited_eff_vis,
parent_id.level(),
- &mut *self.r,
+ tcx,
);
}
fn update_def(&mut self, def_id: LocalDefId, nominal_vis: Visibility, parent_id: ParentId<'a>) {
let private_vis = self.cheap_private_vis(parent_id);
let inherited_eff_vis = self.effective_vis_or_private(parent_id);
+ let tcx = self.r.tcx;
self.changed |= self.def_effective_visibilities.update(
def_id,
nominal_vis,
- |r| (private_vis.unwrap_or_else(|| r.private_vis_def(def_id)), r),
+ || private_vis.unwrap_or_else(|| self.r.private_vis_def(def_id)),
inherited_eff_vis,
parent_id.level(),
- &mut *self.r,
+ tcx,
);
}
@@ -192,7 +186,7 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
}
}
-impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
+impl<'r, 'ast, 'tcx> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r, 'tcx> {
fn visit_item(&mut self, item: &'ast ast::Item) {
let def_id = self.r.local_def_id(item.id);
// Update effective visibilities of nested items.
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 2c4427746..867363f42 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -38,7 +38,7 @@ pub(crate) struct NameAlreadyUsedInParameterList {
#[primary_span]
#[label]
pub(crate) span: Span,
- #[label(first_use_of_name)]
+ #[label(resolve_first_use_of_name)]
pub(crate) first_use_span: Span,
pub(crate) name: Symbol,
}
@@ -121,7 +121,7 @@ pub(crate) struct VariableBoundWithDifferentMode {
#[primary_span]
#[label]
pub(crate) span: Span,
- #[label(first_binding_span)]
+ #[label(resolve_first_binding_span)]
pub(crate) first_binding_span: Span,
pub(crate) variable_name: Symbol,
}
@@ -293,7 +293,7 @@ pub(crate) struct BindingShadowsSomethingUnacceptable<'a> {
pub(crate) article: &'a str,
#[subdiagnostic]
pub(crate) sub_suggestion: Option<BindingShadowsSomethingUnacceptableSuggestion>,
- #[label(label_shadowed_binding)]
+ #[label(resolve_label_shadowed_binding)]
pub(crate) shadowed_binding_span: Span,
pub(crate) participle: &'a str,
pub(crate) name: Symbol,
@@ -369,7 +369,7 @@ pub(crate) struct UnreachableLabel {
#[label]
pub(crate) span: Span,
pub(crate) name: Symbol,
- #[label(label_definition_span)]
+ #[label(resolve_label_definition_span)]
pub(crate) definition_span: Span,
#[subdiagnostic]
pub(crate) sub_suggestion: Option<UnreachableLabelSubSuggestion>,
@@ -413,7 +413,7 @@ pub(crate) struct TraitImplMismatch {
pub(crate) span: Span,
pub(crate) name: Symbol,
pub(crate) kind: String,
- #[label(label_trait_item)]
+ #[label(resolve_label_trait_item)]
pub(crate) trait_item_span: Span,
pub(crate) trait_path: String,
pub(crate) code: String,
@@ -434,9 +434,9 @@ pub(crate) struct TraitImplDuplicate {
#[primary_span]
#[label]
pub(crate) span: Span,
- #[label(old_span_label)]
+ #[label(resolve_old_span_label)]
pub(crate) old_span: Span,
- #[label(trait_item_span)]
+ #[label(resolve_trait_item_span)]
pub(crate) trait_item_span: Span,
pub(crate) name: Symbol,
}
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index a84652a31..52f0b65fa 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -7,7 +7,6 @@ use rustc_middle::ty;
use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK;
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_span::def_id::LocalDefId;
-use rustc_span::edition::Edition;
use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext};
use rustc_span::symbol::{kw, Ident};
use rustc_span::{Span, DUMMY_SP};
@@ -29,7 +28,7 @@ use RibKind::*;
type Visibility = ty::Visibility<LocalDefId>;
-impl<'a> Resolver<'a> {
+impl<'a, 'tcx> Resolver<'a, 'tcx> {
/// A generic scope visitor.
/// Visits scopes in order to resolve some identifier in them or perform other actions.
/// If the callback returns `Some` result, we stop visiting scopes and return it.
@@ -86,7 +85,7 @@ impl<'a> Resolver<'a> {
// 4c. Standard library prelude (de-facto closed, controlled).
// 6. Language prelude: builtin attributes (closed, controlled).
- let rust_2015 = ctxt.edition() == Edition::Edition2015;
+ let rust_2015 = ctxt.edition().is_rust_2015();
let (ns, macro_kind, is_absolute_path) = match scope_set {
ScopeSet::All(ns, _) => (ns, None, false),
ScopeSet::AbsolutePath(ns) => (ns, None, true),
@@ -369,7 +368,7 @@ impl<'a> Resolver<'a> {
/// This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during
/// expansion and import resolution (perhaps they can be merged in the future).
/// The function is used for resolving initial segments of macro paths (e.g., `foo` in
- /// `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition.
+ /// `foo::bar!();` or `foo!();`) and also for import paths on 2018 edition.
#[instrument(level = "debug", skip(self, scope_set))]
pub(crate) fn early_resolve_ident_in_lexical_scope(
&mut self,
@@ -1180,7 +1179,7 @@ impl<'a> Resolver<'a> {
}
ConstantItemRibKind(trivial, _) => {
- let features = self.session.features_untracked();
+ let features = self.tcx.sess.features_untracked();
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
if !(trivial == ConstantHasGenerics::Yes
|| features.generic_const_exprs)
@@ -1209,7 +1208,7 @@ impl<'a> Resolver<'a> {
is_type: true,
},
);
- self.session.delay_span_bug(span, CG_BUG_STR);
+ self.tcx.sess.delay_span_bug(span, CG_BUG_STR);
}
return Res::Err;
@@ -1256,7 +1255,7 @@ impl<'a> Resolver<'a> {
| ForwardGenericParamBanRibKind => continue,
ConstantItemRibKind(trivial, _) => {
- let features = self.session.features_untracked();
+ let features = self.tcx.sess.features_untracked();
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
if !(trivial == ConstantHasGenerics::Yes
|| features.generic_const_exprs)
@@ -1269,7 +1268,7 @@ impl<'a> Resolver<'a> {
is_type: false,
},
);
- self.session.delay_span_bug(span, CG_BUG_STR);
+ self.tcx.sess.delay_span_bug(span, CG_BUG_STR);
}
return Res::Err;
@@ -1398,7 +1397,10 @@ impl<'a> Resolver<'a> {
module = Some(ModuleOrUniformRoot::ExternPrelude);
continue;
}
- if name == kw::PathRoot && ident.span.rust_2015() && self.session.rust_2018() {
+ if name == kw::PathRoot
+ && ident.span.is_rust_2015()
+ && self.tcx.sess.rust_2018()
+ {
// `::a::b` from 2015 macro on 2018 global edition
module = Some(ModuleOrUniformRoot::CrateRootAndExternPrelude);
continue;
@@ -1494,7 +1496,8 @@ impl<'a> Resolver<'a> {
record_segment_res(self, res);
} else if res == Res::ToolMod && i + 1 != path.len() {
if binding.is_import() {
- self.session
+ self.tcx
+ .sess
.struct_span_err(
ident.span,
"cannot use a tool module through an import",
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 00f65ac37..4dab0836d 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -21,8 +21,8 @@ use rustc_middle::span_bug;
use rustc_middle::ty;
use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS};
use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::hygiene::LocalExpnId;
-use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::Span;
@@ -33,7 +33,7 @@ type Res = def::Res<NodeId>;
/// Contains data for specific kinds of imports.
#[derive(Clone)]
-pub enum ImportKind<'a> {
+pub(crate) enum ImportKind<'a> {
Single {
/// `source` in `use prefix::source as target`.
source: Ident,
@@ -157,11 +157,11 @@ pub(crate) struct Import<'a> {
}
impl<'a> Import<'a> {
- pub fn is_glob(&self) -> bool {
+ pub(crate) fn is_glob(&self) -> bool {
matches!(self.kind, ImportKind::Glob { .. })
}
- pub fn is_nested(&self) -> bool {
+ pub(crate) fn is_nested(&self) -> bool {
match self.kind {
ImportKind::Single { nested, .. } => nested,
_ => false,
@@ -210,6 +210,17 @@ impl<'a> NameResolution<'a> {
}
}
+/// An error that may be transformed into a diagnostic later. Used to combine multiple unresolved
+/// import errors within the same use tree into a single diagnostic.
+#[derive(Debug, Clone)]
+struct UnresolvedImportError {
+ span: Span,
+ label: Option<String>,
+ note: Option<String>,
+ suggestion: Option<Suggestion>,
+ candidates: Option<Vec<ImportSuggestion>>,
+}
+
// Reexports of the form `pub use foo as bar;` where `foo` is `extern crate foo;`
// are permitted for backward-compatibility under a deprecation lint.
fn pub_use_of_private_extern_crate_hack(import: &Import<'_>, binding: &NameBinding<'_>) -> bool {
@@ -225,7 +236,7 @@ fn pub_use_of_private_extern_crate_hack(import: &Import<'_>, binding: &NameBindi
}
}
-impl<'a> Resolver<'a> {
+impl<'a, 'tcx> Resolver<'a, 'tcx> {
/// Given a binding and an import that resolves to it,
/// return the corresponding binding defined by the import.
pub(crate) fn import(
@@ -333,7 +344,7 @@ impl<'a> Resolver<'a> {
// If the resolution becomes a success, define it in the module's glob importers.
fn update_resolution<T, F>(&mut self, module: Module<'a>, key: BindingKey, f: F) -> T
where
- F: FnOnce(&mut Resolver<'a>, &mut NameResolution<'a>) -> T,
+ F: FnOnce(&mut Resolver<'a, 'tcx>, &mut NameResolution<'a>) -> T,
{
// Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
// during which the resolution might end up getting re-defined via a glob cycle.
@@ -392,24 +403,7 @@ impl<'a> Resolver<'a> {
}
}
}
-}
-
-/// An error that may be transformed into a diagnostic later. Used to combine multiple unresolved
-/// import errors within the same use tree into a single diagnostic.
-#[derive(Debug, Clone)]
-struct UnresolvedImportError {
- span: Span,
- label: Option<String>,
- note: Option<String>,
- suggestion: Option<Suggestion>,
- candidates: Option<Vec<ImportSuggestion>>,
-}
-
-pub struct ImportResolver<'a, 'b> {
- pub r: &'a mut Resolver<'b>,
-}
-impl<'a, 'b> ImportResolver<'a, 'b> {
// Import resolution
//
// This is a fixed-point algorithm. We resolve imports until our efforts
@@ -420,29 +414,29 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
/// Resolves all imports for the crate. This method performs the fixed-
/// point iteration.
- pub fn resolve_imports(&mut self) {
- let mut prev_num_indeterminates = self.r.indeterminate_imports.len() + 1;
- while self.r.indeterminate_imports.len() < prev_num_indeterminates {
- prev_num_indeterminates = self.r.indeterminate_imports.len();
- for import in mem::take(&mut self.r.indeterminate_imports) {
+ pub(crate) fn resolve_imports(&mut self) {
+ let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1;
+ while self.indeterminate_imports.len() < prev_num_indeterminates {
+ prev_num_indeterminates = self.indeterminate_imports.len();
+ for import in mem::take(&mut self.indeterminate_imports) {
match self.resolve_import(&import) {
- true => self.r.determined_imports.push(import),
- false => self.r.indeterminate_imports.push(import),
+ true => self.determined_imports.push(import),
+ false => self.indeterminate_imports.push(import),
}
}
}
}
- pub fn finalize_imports(&mut self) {
- for module in self.r.arenas.local_modules().iter() {
+ pub(crate) fn finalize_imports(&mut self) {
+ for module in self.arenas.local_modules().iter() {
self.finalize_resolutions_in(module);
}
let mut seen_spans = FxHashSet::default();
let mut errors = vec![];
let mut prev_root_id: NodeId = NodeId::from_u32(0);
- let determined_imports = mem::take(&mut self.r.determined_imports);
- let indeterminate_imports = mem::take(&mut self.r.indeterminate_imports);
+ let determined_imports = mem::take(&mut self.determined_imports);
+ let indeterminate_imports = mem::take(&mut self.indeterminate_imports);
for (is_indeterminate, import) in determined_imports
.into_iter()
@@ -453,7 +447,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
// If this import is unresolved then create a dummy import
// resolution for it so that later resolve stages won't complain.
- self.r.import_dummy_binding(import);
+ self.import_dummy_binding(import);
if let Some(err) = unresolved_import_error {
if let ImportKind::Single { source, ref source_bindings, .. } = import.kind {
@@ -526,7 +520,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
.collect::<Vec<_>>();
let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
- let mut diag = struct_span_err!(self.r.session, span, E0432, "{}", &msg);
+ let mut diag = struct_span_err!(self.tcx.sess, span, E0432, "{}", &msg);
if let Some((_, UnresolvedImportError { note: Some(note), .. })) = errors.iter().last() {
diag.note(note);
@@ -548,8 +542,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
if let Some(candidates) = &err.candidates {
match &import.kind {
ImportKind::Single { nested: false, source, target, .. } => import_candidates(
- self.r.session,
- &self.r.untracked.source_span,
+ self.tcx,
&mut diag,
Some(err.span),
&candidates,
@@ -561,8 +554,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
),
ImportKind::Single { nested: true, source, target, .. } => {
import_candidates(
- self.r.session,
- &self.r.untracked.source_span,
+ self.tcx,
&mut diag,
None,
&candidates,
@@ -583,7 +575,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
/// Attempts to resolve the given import, returning true if its resolution is determined.
/// If successful, the resolved bindings are written into the module.
- fn resolve_import(&mut self, import: &'b Import<'b>) -> bool {
+ fn resolve_import(&mut self, import: &'a Import<'a>) -> bool {
debug!(
"(resolving import for module) resolving import `{}::...` in `{}`",
Segment::names_to_string(&import.module_path),
@@ -596,8 +588,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
// For better failure detection, pretend that the import will
// not define any names while resolving its module path.
let orig_vis = import.vis.take();
- let path_res =
- self.r.maybe_resolve_path(&import.module_path, None, &import.parent_scope);
+ let path_res = self.maybe_resolve_path(&import.module_path, None, &import.parent_scope);
import.vis.set(orig_vis);
match path_res {
@@ -625,7 +616,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
};
let mut indeterminate = false;
- self.r.per_ns(|this, ns| {
+ self.per_ns(|this, ns| {
if !type_ns_only || ns == TypeNS {
if let Err(Undetermined) = source_bindings[ns].get() {
// For better failure detection, pretend that the import will
@@ -658,7 +649,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
source_binding @ (Ok(..) | Err(Determined)) => {
if source_binding.is_ok() {
let msg = format!("`{}` is not directly importable", target);
- struct_span_err!(this.session, import.span, E0253, "{}", &msg)
+ struct_span_err!(this.tcx.sess, import.span, E0253, "{}", &msg)
.span_label(import.span, "cannot be imported directly")
.emit();
}
@@ -678,15 +669,15 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
///
/// Optionally returns an unresolved import error. This error is buffered and used to
/// consolidate multiple unresolved import errors into a single diagnostic.
- fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImportError> {
+ fn finalize_import(&mut self, import: &'a Import<'a>) -> Option<UnresolvedImportError> {
let orig_vis = import.vis.take();
let ignore_binding = match &import.kind {
ImportKind::Single { target_bindings, .. } => target_bindings[TypeNS].get(),
_ => None,
};
- let prev_ambiguity_errors_len = self.r.ambiguity_errors.len();
+ let prev_ambiguity_errors_len = self.ambiguity_errors.len();
let finalize = Finalize::with_root_span(import.root_id, import.span, import.root_span);
- let path_res = self.r.resolve_path(
+ let path_res = self.resolve_path(
&import.module_path,
None,
&import.parent_scope,
@@ -694,7 +685,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
ignore_binding,
);
- let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
+ let no_ambiguity = self.ambiguity_errors.len() == prev_ambiguity_errors_len;
import.vis.set(orig_vis);
let module = match path_res {
PathResult::Module(module) => {
@@ -703,10 +694,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
if !ModuleOrUniformRoot::same_def(module, initial_module) && no_ambiguity {
span_bug!(import.span, "inconsistent resolution for an import");
}
- } else if self.r.privacy_errors.is_empty() {
+ } else if self.privacy_errors.is_empty() {
let msg = "cannot determine resolution for the import";
let msg_note = "import resolution is stuck, try simplifying other imports";
- self.r.session.struct_span_err(import.span, msg).note(msg_note).emit();
+ self.tcx.sess.struct_span_err(import.span, msg).note(msg_note).emit();
}
module
@@ -714,8 +705,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
if no_ambiguity {
assert!(import.imported_module.get().is_none());
- self.r
- .report_error(span, ResolutionError::FailedToResolve { label, suggestion });
+ self.report_error(span, ResolutionError::FailedToResolve { label, suggestion });
}
return None;
}
@@ -777,7 +767,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
// 2 segments, so the `resolve_path` above won't trigger it.
let mut full_path = import.module_path.clone();
full_path.push(Segment::from_ident(Ident::empty()));
- self.r.lint_if_path_starts_with_module(Some(finalize), &full_path, None);
+ self.lint_if_path_starts_with_module(Some(finalize), &full_path, None);
}
if let ModuleOrUniformRoot::Module(module) = module {
@@ -796,10 +786,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
}
if !is_prelude
&& let Some(max_vis) = max_vis.get()
- && !max_vis.is_at_least(import.expect_vis(), &*self.r)
+ && !max_vis.is_at_least(import.expect_vis(), &*self)
{
let msg = "glob import doesn't reexport anything because no candidate is public enough";
- self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, msg);
+ self.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, msg);
}
return None;
}
@@ -807,7 +797,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
};
let mut all_ns_err = true;
- self.r.per_ns(|this, ns| {
+ self.per_ns(|this, ns| {
if !type_ns_only || ns == TypeNS {
let orig_vis = import.vis.take();
let binding = this.resolve_ident_in_module(
@@ -859,7 +849,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
let msg = "cannot determine resolution for the import";
let msg_note =
"import resolution is stuck, try simplifying other imports";
- this.session.struct_span_err(import.span, msg).note(msg_note).emit();
+ this.tcx.sess.struct_span_err(import.span, msg).note(msg_note).emit();
}
}
Err(..) => {
@@ -876,7 +866,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
if all_ns_err {
let mut all_ns_failed = true;
- self.r.per_ns(|this, ns| {
+ self.per_ns(|this, ns| {
if !type_ns_only || ns == TypeNS {
let binding = this.resolve_ident_in_module(
module,
@@ -894,9 +884,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
return if all_ns_failed {
let resolutions = match module {
- ModuleOrUniformRoot::Module(module) => {
- Some(self.r.resolutions(module).borrow())
- }
+ ModuleOrUniformRoot::Module(module) => Some(self.resolutions(module).borrow()),
_ => None,
};
let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter());
@@ -965,7 +953,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
};
let parent_suggestion =
- self.r.lookup_import_candidates(ident, TypeNS, &import.parent_scope, |_| true);
+ self.lookup_import_candidates(ident, TypeNS, &import.parent_scope, |_| true);
Some(UnresolvedImportError {
span: import.span,
@@ -987,7 +975,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
let mut reexport_error = None;
let mut any_successful_reexport = false;
let mut crate_private_reexport = false;
- self.r.per_ns(|this, ns| {
+ self.per_ns(|this, ns| {
if let Ok(binding) = source_bindings[ns].get() {
if !binding.vis.is_at_least(import.expect_vis(), &*this) {
reexport_error = Some((ns, binding));
@@ -1012,7 +1000,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
`pub`",
ident
);
- self.r.lint_buffer.buffer_lint(
+ self.lint_buffer.buffer_lint(
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
import_id,
import.span,
@@ -1035,17 +1023,17 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
format!("re-export of private `{}`", ident)
};
- struct_span_err!(self.r.session, import.span, E0365, "{}", error_msg)
+ struct_span_err!(self.tcx.sess, import.span, E0365, "{}", error_msg)
.span_label(import.span, label_msg)
.note(&format!("consider declaring type or module `{}` with `pub`", ident))
.emit();
} else {
let mut err =
- struct_span_err!(self.r.session, import.span, E0364, "{error_msg}");
+ struct_span_err!(self.tcx.sess, import.span, E0364, "{error_msg}");
match binding.kind {
NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id))
// exclude decl_macro
- if self.r.get_macro_by_def_id(def_id).macro_rules =>
+ if self.get_macro_by_def_id(def_id).macro_rules =>
{
err.span_help(
binding.span,
@@ -1071,7 +1059,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
// 2 segments, so the `resolve_path` above won't trigger it.
let mut full_path = import.module_path.clone();
full_path.push(Segment::from_ident(ident));
- self.r.per_ns(|this, ns| {
+ self.per_ns(|this, ns| {
if let Ok(binding) = source_bindings[ns].get() {
this.lint_if_path_starts_with_module(Some(finalize), &full_path, Some(binding));
}
@@ -1081,7 +1069,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
// Record what this import resolves to for later uses in documentation,
// this may resolve to either a value or a type, but for documentation
// purposes it's good enough to just favor one over the other.
- self.r.per_ns(|this, ns| {
+ self.per_ns(|this, ns| {
if let Ok(binding) = source_bindings[ns].get() {
this.import_res_map.entry(import_id).or_default()[ns] = Some(binding.res());
}
@@ -1096,9 +1084,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
fn check_for_redundant_imports(
&mut self,
ident: Ident,
- import: &'b Import<'b>,
- source_bindings: &PerNS<Cell<Result<&'b NameBinding<'b>, Determinacy>>>,
- target_bindings: &PerNS<Cell<Option<&'b NameBinding<'b>>>>,
+ import: &'a Import<'a>,
+ source_bindings: &PerNS<Cell<Result<&'a NameBinding<'a>, Determinacy>>>,
+ target_bindings: &PerNS<Cell<Option<&'a NameBinding<'a>>>>,
target: Ident,
) {
// This function is only called for single imports.
@@ -1119,7 +1107,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
let mut redundant_span = PerNS { value_ns: None, type_ns: None, macro_ns: None };
- self.r.per_ns(|this, ns| {
+ self.per_ns(|this, ns| {
if let Ok(binding) = source_bindings[ns].get() {
if binding.res() == Res::Err {
return;
@@ -1149,7 +1137,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
let mut redundant_spans: Vec<_> = redundant_span.present_items().collect();
redundant_spans.sort();
redundant_spans.dedup();
- self.r.lint_buffer.buffer_lint_with_diagnostic(
+ self.lint_buffer.buffer_lint_with_diagnostic(
UNUSED_IMPORTS,
id,
import.span,
@@ -1159,22 +1147,22 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
}
}
- fn resolve_glob_import(&mut self, import: &'b Import<'b>) {
+ fn resolve_glob_import(&mut self, import: &'a Import<'a>) {
// This function is only called for glob imports.
let ImportKind::Glob { id, is_prelude, .. } = import.kind else { unreachable!() };
let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else {
- self.r.session.span_err(import.span, "cannot glob-import all possible crates");
+ self.tcx.sess.span_err(import.span, "cannot glob-import all possible crates");
return;
};
if module.is_trait() {
- self.r.session.span_err(import.span, "items in traits are not importable");
+ self.tcx.sess.span_err(import.span, "items in traits are not importable");
return;
} else if ptr::eq(module, import.parent_scope.module) {
return;
} else if is_prelude {
- self.r.prelude = Some(module);
+ self.prelude = Some(module);
return;
}
@@ -1184,7 +1172,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
// Ensure that `resolutions` isn't borrowed during `try_define`,
// since it might get updated via a glob cycle.
let bindings = self
- .r
.resolutions(module)
.borrow()
.iter()
@@ -1194,30 +1181,30 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
.collect::<Vec<_>>();
for (mut key, binding) in bindings {
let scope = match key.ident.span.reverse_glob_adjust(module.expansion, import.span) {
- Some(Some(def)) => self.r.expn_def_scope(def),
+ Some(Some(def)) => self.expn_def_scope(def),
Some(None) => import.parent_scope.module,
None => continue,
};
- if self.r.is_accessible_from(binding.vis, scope) {
- let imported_binding = self.r.import(binding, import);
- let _ = self.r.try_define(import.parent_scope.module, key, imported_binding);
+ if self.is_accessible_from(binding.vis, scope) {
+ let imported_binding = self.import(binding, import);
+ let _ = self.try_define(import.parent_scope.module, key, imported_binding);
}
}
// Record the destination of this import
- self.r.record_partial_res(id, PartialRes::new(module.res().unwrap()));
+ self.record_partial_res(id, PartialRes::new(module.res().unwrap()));
}
// Miscellaneous post-processing, including recording re-exports,
// reporting conflicts, and reporting unresolved imports.
- fn finalize_resolutions_in(&mut self, module: Module<'b>) {
+ fn finalize_resolutions_in(&mut self, module: Module<'a>) {
// Since import resolution is finished, globs will not define any more names.
*module.globs.borrow_mut() = Vec::new();
if let Some(def_id) = module.opt_def_id() {
let mut reexports = Vec::new();
- module.for_each_child(self.r, |this, ident, _, binding| {
+ module.for_each_child(self, |this, ident, _, binding| {
if let Some(res) = this.is_reexport(binding) {
reexports.push(ModChild {
ident,
@@ -1232,7 +1219,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
if !reexports.is_empty() {
// Call to `expect_local` should be fine because current
// code is only called for local modules.
- self.r.reexport_map.insert(def_id.expect_local(), reexports);
+ self.reexport_map.insert(def_id.expect_local(), reexports);
}
}
}
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 83932c089..7df17376b 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -8,7 +8,7 @@
use RibKind::*;
-use crate::{path_names_to_string, BindingError, Finalize, LexicalScopeBinding};
+use crate::{path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding};
use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult};
use crate::{ResolutionError, Resolver, Segment, UseError};
@@ -21,15 +21,16 @@ use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate};
-use rustc_middle::middle::resolve_lifetime::Set1;
+use rustc_middle::middle::resolve_bound_vars::Set1;
use rustc_middle::ty::DefIdTree;
use rustc_middle::{bug, span_bug};
+use rustc_session::config::{CrateType, ResolveDocLinks};
use rustc_session::lint;
+use rustc_span::source_map::{respan, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, Span};
+use rustc_span::{BytePos, Span, SyntaxContext};
use smallvec::{smallvec, SmallVec};
-use rustc_span::source_map::{respan, Spanned};
use std::assert_matches::debug_assert_matches;
use std::borrow::Cow;
use std::collections::{hash_map::Entry, BTreeSet};
@@ -55,7 +56,7 @@ struct BindingInfo {
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum PatternSource {
+pub(crate) enum PatternSource {
Match,
Let,
For,
@@ -69,7 +70,7 @@ enum IsRepeatExpr {
}
impl PatternSource {
- pub fn descr(self) -> &'static str {
+ fn descr(self) -> &'static str {
match self {
PatternSource::Match => "match binding",
PatternSource::Let => "let binding",
@@ -493,6 +494,30 @@ impl<'a> PathSource<'a> {
}
}
+/// At this point for most items we can answer whether that item is exported or not,
+/// but some items like impls require type information to determine exported-ness, so we make a
+/// conservative estimate for them (e.g. based on nominal visibility).
+#[derive(Clone, Copy)]
+enum MaybeExported<'a> {
+ Ok(NodeId),
+ Impl(Option<DefId>),
+ ImplItem(Result<DefId, &'a Visibility>),
+}
+
+impl MaybeExported<'_> {
+ fn eval(self, r: &Resolver<'_, '_>) -> bool {
+ let def_id = match self {
+ MaybeExported::Ok(node_id) => Some(r.local_def_id(node_id)),
+ MaybeExported::Impl(Some(trait_def_id)) | MaybeExported::ImplItem(Ok(trait_def_id)) => {
+ trait_def_id.as_local()
+ }
+ MaybeExported::Impl(None) => return true,
+ MaybeExported::ImplItem(Err(vis)) => return vis.kind.is_pub(),
+ };
+ def_id.map_or(true, |def_id| r.effective_visibilities.is_exported(def_id))
+ }
+}
+
#[derive(Default)]
struct DiagnosticMetadata<'ast> {
/// The current trait's associated items' ident, used for diagnostic suggestions.
@@ -559,8 +584,8 @@ struct DiagnosticMetadata<'ast> {
current_elision_failures: Vec<MissingLifetime>,
}
-struct LateResolutionVisitor<'a, 'b, 'ast> {
- r: &'b mut Resolver<'a>,
+struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
+ r: &'b mut Resolver<'a, 'tcx>,
/// The module that represents the current item scope.
parent_scope: ParentScope<'a>,
@@ -603,7 +628,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast> {
}
/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
-impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
+impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
fn visit_attribute(&mut self, _: &'ast Attribute) {
// We do not want to resolve expressions that appear in attributes,
// as they do not correspond to actual code.
@@ -620,7 +645,9 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
self.resolve_arm(arm);
}
fn visit_block(&mut self, block: &'ast Block) {
+ let old_macro_rules = self.parent_scope.macro_rules;
self.resolve_block(block);
+ self.parent_scope.macro_rules = old_macro_rules;
}
fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
// We deal with repeat expressions explicitly in `resolve_expr`.
@@ -655,7 +682,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
// Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
// NodeId `ty.id`.
// This span will be used in case of elision failure.
- let span = self.r.session.source_map().start_point(ty.span);
+ let span = self.r.tcx.sess.source_map().start_point(ty.span);
self.resolve_elided_lifetime(ty.id, span);
visit::walk_ty(self, ty);
}
@@ -771,6 +798,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
);
}
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
+ self.resolve_doc_links(&foreign_item.attrs, MaybeExported::Ok(foreign_item.id));
match foreign_item.kind {
ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
self.with_generic_param_rib(
@@ -1159,10 +1187,20 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
})
});
}
+
+ fn visit_variant(&mut self, v: &'ast Variant) {
+ self.resolve_doc_links(&v.attrs, MaybeExported::Ok(v.id));
+ visit::walk_variant(self, v)
+ }
+
+ fn visit_field_def(&mut self, f: &'ast FieldDef) {
+ self.resolve_doc_links(&f.attrs, MaybeExported::Ok(f.id));
+ visit::walk_field_def(self, f)
+ }
}
-impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
- fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b, 'ast> {
+impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
+ fn new(resolver: &'b mut Resolver<'a, 'tcx>) -> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// During late resolution we only track the module component of the parent scope,
// although it may be useful to track other components as well for diagnostics.
let graph_root = resolver.graph_root;
@@ -1533,7 +1571,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
("`'_` cannot be used here", "`'_` is a reserved lifetime name")
};
let mut diag = rustc_errors::struct_span_err!(
- self.r.session,
+ self.r.tcx.sess,
lifetime.ident.span,
E0637,
"{}",
@@ -1710,7 +1748,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// impl Foo for std::cell::Ref<u32> // note lack of '_
// async fn foo(_: std::cell::Ref<u32>) { ... }
LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } => {
- let sess = self.r.session;
+ let sess = self.r.tcx.sess;
let mut err = rustc_errors::struct_span_err!(
sess,
path_span,
@@ -1725,7 +1763,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
!segment.has_generic_args,
elided_lifetime_span,
);
- err.note("assuming a `'static` lifetime...");
err.emit();
should_lint = false;
@@ -1992,13 +2029,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
/// List all the lifetimes that appear in the provided type.
fn find_lifetime_for_self(&self, ty: &'ast Ty) -> Set1<LifetimeRes> {
- struct SelfVisitor<'r, 'a> {
- r: &'r Resolver<'a>,
+ struct SelfVisitor<'r, 'a, 'tcx> {
+ r: &'r Resolver<'a, 'tcx>,
impl_self: Option<Res>,
lifetime: Set1<LifetimeRes>,
}
- impl SelfVisitor<'_, '_> {
+ impl SelfVisitor<'_, '_, '_> {
// Look for `self: &'a Self` - also desugared from `&'a self`,
// and if that matches, use it for elision and return early.
fn is_self_ty(&self, ty: &Ty) -> bool {
@@ -2016,7 +2053,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
}
}
- impl<'a> Visitor<'a> for SelfVisitor<'_, '_> {
+ impl<'a> Visitor<'a> for SelfVisitor<'_, '_, '_> {
fn visit_ty(&mut self, ty: &'a Ty) {
trace!("SelfVisitor considering ty={:?}", ty);
if let TyKind::Ref(lt, ref mt) = ty.kind && self.is_self_ty(&mt.ty) {
@@ -2145,7 +2182,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
let segments = &use_tree.prefix.segments;
if !segments.is_empty() {
let ident = segments[0].ident;
- if ident.is_path_segment_keyword() || ident.span.rust_2015() {
+ if ident.is_path_segment_keyword() || ident.span.is_rust_2015() {
return;
}
@@ -2157,7 +2194,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
let what = if ns == TypeNS { "type parameters" } else { "local variables" };
if this.should_report_errs() {
this.r
- .session
+ .tcx
+ .sess
.span_err(ident.span, &format!("imports cannot refer to {}", what));
}
};
@@ -2185,6 +2223,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
}
fn resolve_item(&mut self, item: &'ast Item) {
+ let mod_inner_docs =
+ matches!(item.kind, ItemKind::Mod(..)) && rustdoc::inner_docs(&item.attrs);
+ if !mod_inner_docs && !matches!(item.kind, ItemKind::Impl(..)) {
+ self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id));
+ }
+
let name = item.ident.name;
debug!("(resolving item) resolving {} ({:?})", name, item.kind);
@@ -2229,7 +2273,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
..
}) => {
self.diagnostic_metadata.current_impl_items = Some(impl_items);
- self.resolve_implementation(generics, of_trait, &self_ty, item.id, impl_items);
+ self.resolve_implementation(
+ &item.attrs,
+ generics,
+ of_trait,
+ &self_ty,
+ item.id,
+ impl_items,
+ );
self.diagnostic_metadata.current_impl_items = None;
}
@@ -2274,9 +2325,20 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
);
}
- ItemKind::Mod(..) | ItemKind::ForeignMod(_) => {
+ ItemKind::Mod(..) => {
self.with_scope(item.id, |this| {
+ if mod_inner_docs {
+ this.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id));
+ }
+ let old_macro_rules = this.parent_scope.macro_rules;
visit::walk_item(this, item);
+ // Maintain macro_rules scopes in the same way as during early resolution
+ // for diagnostics and doc links.
+ if item.attrs.iter().all(|attr| {
+ !attr.has_name(sym::macro_use) && !attr.has_name(sym::macro_escape)
+ }) {
+ this.parent_scope.macro_rules = old_macro_rules;
+ }
});
}
@@ -2309,14 +2371,21 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.future_proof_import(use_tree);
}
- ItemKind::ExternCrate(..) | ItemKind::MacroDef(..) => {
- // do nothing, these are just around to be encoded
+ ItemKind::MacroDef(ref macro_def) => {
+ // Maintain macro_rules scopes in the same way as during early resolution
+ // for diagnostics and doc links.
+ if macro_def.macro_rules {
+ let def_id = self.r.local_def_id(item.id);
+ self.parent_scope.macro_rules = self.r.macro_rules_scopes[&def_id];
+ }
}
- ItemKind::GlobalAsm(_) => {
+ ItemKind::ForeignMod(_) | ItemKind::GlobalAsm(_) => {
visit::walk_item(self, item);
}
+ ItemKind::ExternCrate(..) => {}
+
ItemKind::MacCall(_) => panic!("unexpanded macro in resolve!"),
}
}
@@ -2370,7 +2439,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
if let GenericParamKind::Lifetime = param.kind
&& let Some(&original) = seen_lifetimes.get(&ident)
{
- diagnostics::signal_lifetime_shadowing(self.r.session, original, param.ident);
+ diagnostics::signal_lifetime_shadowing(self.r.tcx.sess, original, param.ident);
// Record lifetime res, so lowering knows there is something fishy.
self.record_lifetime_param(param.id, LifetimeRes::Error);
continue;
@@ -2394,7 +2463,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
if param.ident.name == kw::UnderscoreLifetime {
rustc_errors::struct_span_err!(
- self.r.session,
+ self.r.tcx.sess,
param.ident.span,
E0637,
"`'_` cannot be used here"
@@ -2408,7 +2477,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
if param.ident.name == kw::StaticLifetime {
rustc_errors::struct_span_err!(
- self.r.session,
+ self.r.tcx.sess,
param.ident.span,
E0262,
"invalid lifetime parameter name: `{}`",
@@ -2437,7 +2506,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
let res = match kind {
ItemRibKind(..) | AssocItemRibKind => Res::Def(def_kind, def_id.to_def_id()),
- NormalRibKind => Res::Err,
+ NormalRibKind => {
+ if self.r.tcx.sess.features_untracked().non_lifetime_binders {
+ Res::Def(def_kind, def_id.to_def_id())
+ } else {
+ Res::Err
+ }
+ }
_ => span_bug!(param.ident.span, "Unexpected rib kind {:?}", kind),
};
self.r.record_partial_res(param.id, PartialRes::new(res));
@@ -2544,6 +2619,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
};
for item in trait_items {
+ self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id));
match &item.kind {
AssocItemKind::Const(_, ty, default) => {
self.visit_ty(ty);
@@ -2631,6 +2707,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
fn resolve_implementation(
&mut self,
+ attrs: &[ast::Attribute],
generics: &'ast Generics,
opt_trait_reference: &'ast Option<TraitRef>,
self_type: &'ast Ty,
@@ -2661,6 +2738,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
opt_trait_reference.as_ref(),
self_type,
|this, trait_id| {
+ this.resolve_doc_links(attrs, MaybeExported::Impl(trait_id));
+
let item_def_id = this.r.local_def_id(item_id);
// Register the trait definitions from here.
@@ -2694,7 +2773,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
let mut seen_trait_items = Default::default();
for item in impl_items {
- this.resolve_impl_item(&**item, &mut seen_trait_items);
+ this.resolve_impl_item(&**item, &mut seen_trait_items, trait_id);
}
});
});
@@ -2712,8 +2791,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
&mut self,
item: &'ast AssocItem,
seen_trait_items: &mut FxHashMap<DefId, Span>,
+ trait_id: Option<DefId>,
) {
use crate::ResolutionError::*;
+ self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis)));
match &item.kind {
AssocItemKind::Const(_, ty, default) => {
debug!("resolve_implementation AssocItemKind::Const");
@@ -3304,7 +3385,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
Res::SelfCtor(_) => {
// We resolve `Self` in pattern position as an ident sometimes during recovery,
// so delay a bug instead of ICEing.
- self.r.session.delay_span_bug(
+ self.r.tcx.sess.delay_span_bug(
ident.span,
"unexpected `SelfCtor` in pattern, expected identifier"
);
@@ -3584,7 +3665,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
#[inline]
/// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items.
fn should_report_errs(&self) -> bool {
- !(self.r.session.opts.actually_rustdoc && self.in_func_body)
+ !(self.r.tcx.sess.opts.actually_rustdoc && self.in_func_body)
}
// Resolve in alternative namespaces if resolution in the primary namespace fails.
@@ -3749,7 +3830,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
}
if let Ok((_, orig_span)) = self.resolve_label(label.ident) {
- diagnostics::signal_label_shadowing(self.r.session, orig_span, label.ident)
+ diagnostics::signal_label_shadowing(self.r.tcx.sess, orig_span, label.ident)
}
self.with_label_rib(NormalRibKind, |this| {
@@ -4055,9 +4136,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &'ast Expr) {
match expr.kind {
ExprKind::Field(_, ident) => {
- // FIXME(#6890): Even though you can't treat a method like a
- // field, we need to add any trait methods we find that match
- // the field name so that we can do some nice error reporting
+ // #6890: Even though you can't treat a method like a field,
+ // we need to add any trait methods we find that match the
+ // field name so that we can do some nice error reporting
// later on in typeck.
let traits = self.traits_in_scope(ident, ValueNS);
self.r.trait_map.insert(expr.id, traits);
@@ -4116,15 +4197,116 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params);
}
}
+
+ fn resolve_and_cache_rustdoc_path(&mut self, path_str: &str, ns: Namespace) -> bool {
+ // FIXME: This caching may be incorrect in case of multiple `macro_rules`
+ // items with the same name in the same module.
+ // Also hygiene is not considered.
+ let mut doc_link_resolutions = std::mem::take(&mut self.r.doc_link_resolutions);
+ let res = doc_link_resolutions
+ .entry(self.parent_scope.module.nearest_parent_mod().expect_local())
+ .or_default()
+ .entry((Symbol::intern(path_str), ns))
+ .or_insert_with_key(|(path, ns)| {
+ let res = self.r.resolve_rustdoc_path(path.as_str(), *ns, self.parent_scope);
+ if let Some(res) = res
+ && let Some(def_id) = res.opt_def_id()
+ && !def_id.is_local()
+ && self.r.tcx.sess.crate_types().contains(&CrateType::ProcMacro)
+ && matches!(self.r.tcx.sess.opts.resolve_doc_links, ResolveDocLinks::ExportedMetadata) {
+ // Encoding foreign def ids in proc macro crate metadata will ICE.
+ return None;
+ }
+ res
+ })
+ .is_some();
+ self.r.doc_link_resolutions = doc_link_resolutions;
+ res
+ }
+
+ fn resolve_doc_links(&mut self, attrs: &[Attribute], maybe_exported: MaybeExported<'_>) {
+ match self.r.tcx.sess.opts.resolve_doc_links {
+ ResolveDocLinks::None => return,
+ ResolveDocLinks::ExportedMetadata
+ if !self.r.tcx.sess.crate_types().iter().copied().any(CrateType::has_metadata)
+ || !maybe_exported.eval(self.r) =>
+ {
+ return;
+ }
+ ResolveDocLinks::Exported if !maybe_exported.eval(self.r) => {
+ return;
+ }
+ ResolveDocLinks::ExportedMetadata
+ | ResolveDocLinks::Exported
+ | ResolveDocLinks::All => {}
+ }
+
+ if !attrs.iter().any(|attr| attr.may_have_doc_links()) {
+ return;
+ }
+
+ let mut need_traits_in_scope = false;
+ for path_str in rustdoc::attrs_to_preprocessed_links(attrs) {
+ // Resolve all namespaces due to no disambiguator or for diagnostics.
+ let mut any_resolved = false;
+ let mut need_assoc = false;
+ for ns in [TypeNS, ValueNS, MacroNS] {
+ if self.resolve_and_cache_rustdoc_path(&path_str, ns) {
+ any_resolved = true;
+ } else if ns != MacroNS {
+ need_assoc = true;
+ }
+ }
+
+ // Resolve all prefixes for type-relative resolution or for diagnostics.
+ if need_assoc || !any_resolved {
+ let mut path = &path_str[..];
+ while let Some(idx) = path.rfind("::") {
+ path = &path[..idx];
+ need_traits_in_scope = true;
+ for ns in [TypeNS, ValueNS, MacroNS] {
+ self.resolve_and_cache_rustdoc_path(path, ns);
+ }
+ }
+ }
+ }
+
+ if need_traits_in_scope {
+ // FIXME: hygiene is not considered.
+ let mut doc_link_traits_in_scope = std::mem::take(&mut self.r.doc_link_traits_in_scope);
+ doc_link_traits_in_scope
+ .entry(self.parent_scope.module.nearest_parent_mod().expect_local())
+ .or_insert_with(|| {
+ self.r
+ .traits_in_scope(None, &self.parent_scope, SyntaxContext::root(), None)
+ .into_iter()
+ .filter_map(|tr| {
+ if !tr.def_id.is_local()
+ && self.r.tcx.sess.crate_types().contains(&CrateType::ProcMacro)
+ && matches!(
+ self.r.tcx.sess.opts.resolve_doc_links,
+ ResolveDocLinks::ExportedMetadata
+ )
+ {
+ // Encoding foreign def ids in proc macro crate metadata will ICE.
+ return None;
+ }
+ Some(tr.def_id)
+ })
+ .collect()
+ });
+ self.r.doc_link_traits_in_scope = doc_link_traits_in_scope;
+ }
+ }
}
-struct LifetimeCountVisitor<'a, 'b> {
- r: &'b mut Resolver<'a>,
+struct LifetimeCountVisitor<'a, 'b, 'tcx> {
+ r: &'b mut Resolver<'a, 'tcx>,
}
/// Walks the whole crate in DFS order, visiting each item, counting the declared number of
/// lifetime generic parameters.
-impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_> {
+impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> {
fn visit_item(&mut self, item: &'ast Item) {
match &item.kind {
ItemKind::TyAlias(box TyAlias { ref generics, .. })
@@ -4158,10 +4340,11 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_> {
}
}
-impl<'a> Resolver<'a> {
+impl<'a, 'tcx> Resolver<'a, 'tcx> {
pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) {
visit::walk_crate(&mut LifetimeCountVisitor { r: self }, krate);
let mut late_resolution_visitor = LateResolutionVisitor::new(self);
+ late_resolution_visitor.resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID));
visit::walk_crate(&mut late_resolution_visitor, krate);
for (id, span) in late_resolution_visitor.diagnostic_metadata.unused_labels.iter() {
self.lint_buffer.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label");
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 6d448433e..b8ddc4552 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -25,9 +25,9 @@ use rustc_middle::ty::DefIdTree;
use rustc_session::lint;
use rustc_session::parse::feature_err;
use rustc_session::Session;
+use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::edition::Edition;
use rustc_span::hygiene::MacroKind;
-use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, Span};
@@ -166,11 +166,11 @@ impl TypoCandidate {
}
}
-impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
+impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
fn def_span(&self, def_id: DefId) -> Option<Span> {
match def_id.krate {
LOCAL_CRATE => self.r.opt_span(def_id),
- _ => Some(self.r.cstore().get_span_untracked(def_id, self.r.session)),
+ _ => Some(self.r.cstore().get_span_untracked(def_id, self.r.tcx.sess)),
}
}
@@ -200,7 +200,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
Res::Def(DefKind::Fn, _) => {
// Verify whether this is a fn call or an Fn used as a type.
self.r
- .session
+ .tcx
+ .sess
.source_map()
.span_to_snippet(span)
.map(|snippet| snippet.ends_with(')'))
@@ -227,20 +228,27 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
&& let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt()
&& let Some(items) = self.diagnostic_metadata.current_impl_items
&& let Some(item) = items.iter().find(|i| {
- if let AssocItemKind::Fn(_) = &i.kind && i.ident.name == item_str.name
+ if let AssocItemKind::Fn(..) | AssocItemKind::Const(..) = &i.kind
+ && i.ident.name == item_str.name
{
debug!(?item_str.name);
return true
}
false
})
- && let AssocItemKind::Fn(fn_) = &item.kind
{
- debug!(?fn_);
- let self_sugg = if fn_.sig.decl.has_self() { "self." } else { "Self::" };
+ let self_sugg = match &item.kind {
+ AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => "self.",
+ _ => "Self::",
+ };
+
Some((
item_span.shrink_to_lo(),
- "consider using the associated function",
+ match &item.kind {
+ AssocItemKind::Fn(..) => "consider using the associated function",
+ AssocItemKind::Const(..) => "consider using the associated constant",
+ _ => unreachable!("item kind was filtered above"),
+ },
self_sugg.to_string()
))
} else {
@@ -248,7 +256,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
};
(String::new(), "this scope".to_string(), suggestion)
} else if path.len() == 2 && path[0].ident.name == kw::PathRoot {
- if self.r.session.edition() > Edition::Edition2015 {
+ if self.r.tcx.sess.edition() > Edition::Edition2015 {
// In edition 2018 onwards, the `::foo` syntax may only pull from the extern prelude
// which overrides all other expectations of item type
expected = "crate";
@@ -311,12 +319,12 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
span: Span,
source: PathSource<'_>,
res: Option<Res>,
- ) -> (DiagnosticBuilder<'a, ErrorGuaranteed>, Vec<ImportSuggestion>) {
+ ) -> (DiagnosticBuilder<'tcx, ErrorGuaranteed>, Vec<ImportSuggestion>) {
debug!(?res, ?source);
let base_error = self.make_base_error(path, span, source, res);
let code = source.error_code(res.is_some());
let mut err =
- self.r.session.struct_span_err_with_code(base_error.span, &base_error.msg, code);
+ self.r.tcx.sess.struct_span_err_with_code(base_error.span, &base_error.msg, code);
self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
@@ -425,7 +433,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
} else {
(
self.r
- .session
+ .tcx
+ .sess
.source_map()
.span_through_char(*fn_span, '(')
.shrink_to_hi(),
@@ -498,7 +507,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
{
if self
.r
- .session
+ .tcx
+ .sess
.parse_sess
.type_ascription_path_suggestions
.borrow()
@@ -535,7 +545,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
}
}
- // Try Levenshtein algorithm.
+ // Try finding a suitable replacement.
let typo_sugg =
self.lookup_typo_candidate(path, source.namespace(), is_expected).to_opt_suggestion();
if path.len() == 1 && self.self_type_is_available() {
@@ -589,7 +599,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
if let Some((call_span, args_span)) = self.call_has_self_arg(source) {
let mut args_snippet = String::new();
if let Some(args_span) = args_span {
- if let Ok(snippet) = self.r.session.source_map().span_to_snippet(args_span) {
+ if let Ok(snippet) = self.r.tcx.sess.source_map().span_to_snippet(args_span) {
args_snippet = snippet;
}
}
@@ -725,7 +735,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
let is_in_same_file = &|sp1, sp2| {
- let source_map = self.r.session.source_map();
+ let source_map = self.r.tcx.sess.source_map();
let file1 = source_map.span_to_filename(sp1);
let file2 = source_map.span_to_filename(sp2);
file1 == file2
@@ -763,7 +773,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
_ => {}
}
- // If the trait has a single item (which wasn't matched by Levenshtein), suggest it
+ // If the trait has a single item (which wasn't matched by the algorithm), suggest it
let suggestion = self.get_single_associated_item(&path, &source, is_expected);
if !self.r.add_typo_suggestion(err, suggestion, ident_span) {
fallback = !self.let_binding_suggestion(err, ident_span);
@@ -868,7 +878,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
);
let is_assoc_fn = self.self_type_is_available();
if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function {
- // The current function has a `self' parameter, but we were unable to resolve
+ // The current function has a `self` parameter, but we were unable to resolve
// a reference to `self`. This can only happen if the `self` identifier we
// are resolving came from a different hygiene context.
if fn_kind.decl().inputs.get(0).map_or(false, |p| p.is_self()) {
@@ -888,7 +898,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
.map_or(*span, |ident| span.with_lo(ident.span.hi()));
(
self.r
- .session
+ .tcx
+ .sess
.source_map()
.span_through_char(span, '(')
.shrink_to_hi(),
@@ -942,9 +953,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
&& let PathSource::Trait(_) = source
&& let Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)) = res
&& let Ok(self_ty_str) =
- self.r.session.source_map().span_to_snippet(self_ty.span)
+ self.r.tcx.sess.source_map().span_to_snippet(self_ty.span)
&& let Ok(trait_ref_str) =
- self.r.session.source_map().span_to_snippet(trait_ref.path.span)
+ self.r.tcx.sess.source_map().span_to_snippet(trait_ref.path.span)
{
err.multipart_suggestion(
"`impl` items mention the trait being implemented first and the type it is being implemented for second",
@@ -1088,7 +1099,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
format!(
"{}: {}<{} = {}>",
self.r
- .session
+ .tcx
+ .sess
.source_map()
.span_to_snippet(ty.span) // Account for `<&'a T as Foo>::Bar`.
.unwrap_or_else(|_| constrain_ident.to_string()),
@@ -1157,7 +1169,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
// parser issue where a struct literal is being used on an expression
// where a brace being opened means a block is being started. Look
// ahead for the next text to see if `span` is followed by a `{`.
- let sm = self.r.session.source_map();
+ let sm = self.r.tcx.sess.source_map();
let sp = sm.span_look_ahead(span, None, Some(50));
let followed_by_brace = matches!(sm.span_to_snippet(sp), Ok(ref snippet) if snippet == "{");
// In case this could be a struct literal that needs to be surrounded
@@ -1205,7 +1217,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
true
} else if kind == DefKind::Struct
&& let Some(lhs_source_span) = lhs_span.find_ancestor_inside(expr.span)
- && let Ok(snippet) = self.r.session.source_map().span_to_snippet(lhs_source_span)
+ && let Ok(snippet) = self.r.tcx.sess.source_map().span_to_snippet(lhs_source_span)
{
// The LHS is a type that originates from a macro call.
// We have to add angle brackets around it.
@@ -1336,7 +1348,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
"!",
Applicability::MaybeIncorrect,
);
- if path_str == "try" && span.rust_2015() {
+ if path_str == "try" && span.is_rust_2015() {
err.note("if you want the `try` keyword, you need Rust 2018 or later");
}
}
@@ -1345,11 +1357,11 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
}
(Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
err.span_label(span, "type aliases cannot be used as traits");
- if self.r.session.is_nightly_build() {
+ if self.r.tcx.sess.is_nightly_build() {
let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
`type` alias";
if let Some(span) = self.def_span(def_id) {
- if let Ok(snip) = self.r.session.source_map().span_to_snippet(span) {
+ if let Ok(snip) = self.r.tcx.sess.source_map().span_to_snippet(span) {
// The span contains a type alias so we should be able to
// replace `type` with `trait`.
let snip = snip.replacen("type", "trait", 1);
@@ -1380,7 +1392,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
.last()
.map(|sp| {
self.r
- .session
+ .tcx
+ .sess
.parse_sess
.type_ascription_path_suggestions
.borrow()
@@ -1687,17 +1700,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
let extern_prelude = self.r.extern_prelude.clone();
names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
self.r
- .crate_loader()
- .maybe_process_path_extern(ident.name)
+ .crate_loader(|c| c.maybe_process_path_extern(ident.name))
.and_then(|crate_id| {
let crate_mod =
Res::Def(DefKind::Mod, crate_id.as_def_id());
- if filter_fn(crate_mod) {
- Some(TypoSuggestion::typo_from_ident(*ident, crate_mod))
- } else {
- None
- }
+ filter_fn(crate_mod).then(|| {
+ TypoSuggestion::typo_from_ident(*ident, crate_mod)
+ })
})
}));
@@ -1769,12 +1779,12 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
/// Only used in a specific case of type ascription suggestions
fn get_colon_suggestion_span(&self, start: Span) -> Span {
- let sm = self.r.session.source_map();
+ let sm = self.r.tcx.sess.source_map();
start.to(sm.next_point(start))
}
fn type_ascription_suggestion(&self, err: &mut Diagnostic, base_span: Span) -> bool {
- let sm = self.r.session.source_map();
+ let sm = self.r.tcx.sess.source_map();
let base_snippet = sm.span_to_snippet(base_span);
if let Some(&sp) = self.diagnostic_metadata.current_type_ascription.last() {
if let Ok(snippet) = sm.span_to_snippet(sp) {
@@ -1804,7 +1814,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
show_label = false;
if !self
.r
- .session
+ .tcx
+ .sess
.parse_sess
.type_ascription_path_suggestions
.borrow_mut()
@@ -2237,19 +2248,23 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
}
None => {
debug!(?param.ident, ?param.ident.span);
-
let deletion_span = deletion_span();
- self.r.lint_buffer.buffer_lint_with_diagnostic(
- lint::builtin::UNUSED_LIFETIMES,
- param.id,
- param.ident.span,
- &format!("lifetime parameter `{}` never used", param.ident),
- lint::BuiltinLintDiagnostics::SingleUseLifetime {
- param_span: param.ident.span,
- use_span: None,
- deletion_span,
- },
- );
+ // the give lifetime originates from expanded code so we won't be able to remove it #104432
+ let lifetime_only_in_expanded_code =
+ deletion_span.map(|sp| sp.in_derive_expansion()).unwrap_or(true);
+ if !lifetime_only_in_expanded_code {
+ self.r.lint_buffer.buffer_lint_with_diagnostic(
+ lint::builtin::UNUSED_LIFETIMES,
+ param.id,
+ param.ident.span,
+ &format!("lifetime parameter `{}` never used", param.ident),
+ lint::BuiltinLintDiagnostics::SingleUseLifetime {
+ param_span: param.ident.span,
+ use_span: None,
+ deletion_span,
+ },
+ );
+ }
}
}
}
@@ -2263,7 +2278,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
debug_assert_ne!(lifetime_ref.ident.name, kw::UnderscoreLifetime);
let mut err = if let Some(outer) = outer_lifetime_ref {
let mut err = struct_span_err!(
- self.r.session,
+ self.r.tcx.sess,
lifetime_ref.ident.span,
E0401,
"can't use generic parameters from outer item",
@@ -2273,7 +2288,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
err
} else {
let mut err = struct_span_err!(
- self.r.session,
+ self.r.tcx.sess,
lifetime_ref.ident.span,
E0261,
"use of undeclared lifetime name `{}`",
@@ -2331,8 +2346,13 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
);
(span, sugg)
} else {
- let span =
- self.r.session.source_map().span_through_char(span, '<').shrink_to_hi();
+ let span = self
+ .r
+ .tcx
+ .sess
+ .source_map()
+ .span_through_char(span, '<')
+ .shrink_to_hi();
let sugg = format!("{}, ", name.unwrap_or("'a"));
(span, sugg)
};
@@ -2366,7 +2386,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
pub(crate) fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &ast::Lifetime) {
struct_span_err!(
- self.r.session,
+ self.r.tcx.sess,
lifetime_ref.ident.span,
E0771,
"use of non-static lifetime `{}` in const generic",
@@ -2386,10 +2406,10 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
&self,
lifetime_ref: &ast::Lifetime,
) {
- let feature_active = self.r.session.features_untracked().generic_const_exprs;
+ let feature_active = self.r.tcx.sess.features_untracked().generic_const_exprs;
if !feature_active {
feature_err(
- &self.r.session.parse_sess,
+ &self.r.tcx.sess.parse_sess,
sym::generic_const_exprs,
lifetime_ref.ident.span,
"a non-static lifetime is not allowed in a `const`",
@@ -2407,7 +2427,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
let spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
let mut err = struct_span_err!(
- self.r.session,
+ self.r.tcx.sess,
spans,
E0106,
"missing lifetime specifier{}",
@@ -2615,7 +2635,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
}
/// Report lifetime/lifetime shadowing as an error.
-pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) {
+pub(super) fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) {
let mut err = struct_span_err!(
sess,
shadower.span,
@@ -2630,7 +2650,7 @@ pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) {
/// Shadowing involving a label is only a warning for historical reasons.
//FIXME: make this a proper lint.
-pub fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
+pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
let name = shadower.name;
let shadower = shadower.span;
let mut err = sess.struct_span_warn(
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 1b181b714..1fdfb1a53 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -21,34 +21,34 @@
#[macro_use]
extern crate tracing;
-pub use rustc_hir::def::{Namespace, PerNS};
-
use rustc_arena::{DroplessArena, TypedArena};
use rustc_ast::node_id::NodeMap;
use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID};
use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::intern::Interned;
-use rustc_data_structures::sync::{Lrc, RwLock};
-use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_data_structures::sync::{Lrc, MappedReadGuard};
+use rustc_errors::{
+ Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, SubdiagnosticMessage,
+};
use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind};
-use rustc_hir::def::Namespace::*;
-use rustc_hir::def::{self, CtorOf, DefKind, LifetimeRes, PartialRes};
+use rustc_hir::def::Namespace::{self, *};
+use rustc_hir::def::{self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, PartialRes, PerNS};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_hir::definitions::{DefPathData, Definitions};
+use rustc_hir::definitions::DefPathData;
use rustc_hir::TraitCandidate;
use rustc_index::vec::IndexVec;
+use rustc_macros::fluent_messages;
use rustc_metadata::creader::{CStore, CrateLoader};
use rustc_middle::metadata::ModChild;
use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::span_bug;
-use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools};
+use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools, TyCtxt};
use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs};
use rustc_query_system::ich::StableHashingContext;
-use rustc_session::cstore::{CrateStore, MetadataLoaderDyn, Untracked};
+use rustc_session::cstore::CrateStore;
use rustc_session::lint::LintBuffer;
-use rustc_session::Session;
use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -60,7 +60,7 @@ use std::collections::BTreeSet;
use std::{fmt, ptr};
use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
-use imports::{Import, ImportKind, ImportResolver, NameResolution};
+use imports::{Import, ImportKind, NameResolution};
use late::{HasGenericParams, PathSource, PatternSource};
use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
@@ -78,6 +78,9 @@ mod ident;
mod imports;
mod late;
mod macros;
+pub mod rustdoc;
+
+fluent_messages! { "../locales/en-US.ftl" }
enum Weak {
Yes,
@@ -85,7 +88,7 @@ enum Weak {
}
#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum Determinacy {
+enum Determinacy {
Determined,
Undetermined,
}
@@ -138,17 +141,17 @@ enum ScopeSet<'a> {
/// This struct is currently used only for early resolution (imports and macros),
/// but not for late resolution yet.
#[derive(Clone, Copy, Debug)]
-pub struct ParentScope<'a> {
- pub module: Module<'a>,
+struct ParentScope<'a> {
+ module: Module<'a>,
expansion: LocalExpnId,
- pub macro_rules: MacroRulesScopeRef<'a>,
+ macro_rules: MacroRulesScopeRef<'a>,
derives: &'a [ast::Path],
}
impl<'a> ParentScope<'a> {
/// Creates a parent scope with the passed argument used as the module scope component,
/// and other scope components set to default empty values.
- pub fn module(module: Module<'a>, resolver: &Resolver<'a>) -> ParentScope<'a> {
+ fn module(module: Module<'a>, resolver: &Resolver<'a, '_>) -> ParentScope<'a> {
ParentScope {
module,
expansion: LocalExpnId::ROOT,
@@ -256,7 +259,7 @@ enum VisResolutionError<'a> {
/// A minimal representation of a path segment. We use this in resolve because we synthesize 'path
/// segments' which don't have the rest of an AST or HIR `PathSegment`.
#[derive(Clone, Copy, Debug)]
-pub struct Segment {
+struct Segment {
ident: Ident,
id: Option<NodeId>,
/// Signals whether this `PathSegment` has generic arguments. Used to avoid providing
@@ -379,7 +382,7 @@ impl ModuleOrUniformRoot<'_> {
}
}
-#[derive(Clone, Debug)]
+#[derive(Debug)]
enum PathResult<'a> {
Module(ModuleOrUniformRoot<'a>),
NonModule(PartialRes),
@@ -434,7 +437,7 @@ enum ModuleKind {
impl ModuleKind {
/// Get name of the module.
- pub fn name(&self) -> Option<Symbol> {
+ fn name(&self) -> Option<Symbol> {
match self {
ModuleKind::Block => None,
ModuleKind::Def(.., name) => Some(*name),
@@ -470,7 +473,7 @@ type Resolutions<'a> = RefCell<FxIndexMap<BindingKey, &'a RefCell<NameResolution
/// * curly-braced block with statements
///
/// You can use [`ModuleData::kind`] to determine the kind of module this is.
-pub struct ModuleData<'a> {
+struct ModuleData<'a> {
/// The direct parent module (it may not be a `mod`, however).
parent: Option<Module<'a>>,
/// What kind of module this is, because this may not be a `mod`.
@@ -529,9 +532,9 @@ impl<'a> ModuleData<'a> {
}
}
- fn for_each_child<R, F>(&'a self, resolver: &mut R, mut f: F)
+ fn for_each_child<'tcx, R, F>(&'a self, resolver: &mut R, mut f: F)
where
- R: AsMut<Resolver<'a>>,
+ R: AsMut<Resolver<'a, 'tcx>>,
F: FnMut(&mut R, Ident, Namespace, &'a NameBinding<'a>),
{
for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() {
@@ -542,9 +545,9 @@ impl<'a> ModuleData<'a> {
}
/// This modifies `self` in place. The traits will be stored in `self.traits`.
- fn ensure_traits<R>(&'a self, resolver: &mut R)
+ fn ensure_traits<'tcx, R>(&'a self, resolver: &mut R)
where
- R: AsMut<Resolver<'a>>,
+ R: AsMut<Resolver<'a, 'tcx>>,
{
let mut traits = self.traits.borrow_mut();
if traits.is_none() {
@@ -569,7 +572,7 @@ impl<'a> ModuleData<'a> {
}
// Public for rustdoc.
- pub fn def_id(&self) -> DefId {
+ fn def_id(&self) -> DefId {
self.opt_def_id().expect("`ModuleData::def_id` is called on a block module")
}
@@ -627,7 +630,7 @@ impl<'a> fmt::Debug for ModuleData<'a> {
/// Records a possibly-private value, type, or module definition.
#[derive(Clone, Debug)]
-pub struct NameBinding<'a> {
+struct NameBinding<'a> {
kind: NameBindingKind<'a>,
ambiguity: Option<(&'a NameBinding<'a>, AmbiguityKind)>,
expansion: LocalExpnId,
@@ -635,7 +638,7 @@ pub struct NameBinding<'a> {
vis: ty::Visibility<DefId>,
}
-pub trait ToNameBinding<'a> {
+trait ToNameBinding<'a> {
fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a>;
}
@@ -839,9 +842,9 @@ impl<'a> NameBinding<'a> {
}
#[derive(Default, Clone)]
-pub struct ExternPreludeEntry<'a> {
+struct ExternPreludeEntry<'a> {
extern_crate_item: Option<&'a NameBinding<'a>>,
- pub introduced_by_item: bool,
+ introduced_by_item: bool,
}
/// Used for better errors for E0773
@@ -865,8 +868,8 @@ struct MacroData {
/// The main resolver class.
///
/// This is the visitor that walks the whole crate.
-pub struct Resolver<'a> {
- session: &'a Session,
+pub struct Resolver<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
/// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
expn_that_defined: FxHashMap<LocalDefId, ExpnId>,
@@ -943,23 +946,19 @@ pub struct Resolver<'a> {
has_pub_restricted: bool,
used_imports: FxHashSet<NodeId>,
maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
- maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
/// Privacy errors are delayed until the end in order to deduplicate them.
privacy_errors: Vec<PrivacyError<'a>>,
/// Ambiguity errors are delayed for deduplication.
ambiguity_errors: Vec<AmbiguityError<'a>>,
/// `use` injections are delayed for better placement and deduplication.
- use_injections: Vec<UseError<'a>>,
+ use_injections: Vec<UseError<'tcx>>,
/// Crate-local macro expanded `macro_export` referred to by a module-relative path.
macro_expanded_macro_export_errors: BTreeSet<(Span, Span)>,
arenas: &'a ResolverArenas<'a>,
dummy_binding: &'a NameBinding<'a>,
- local_crate_name: Symbol,
- metadata_loader: Box<MetadataLoaderDyn>,
- untracked: Untracked,
used_extern_options: FxHashSet<Symbol>,
macro_names: FxHashSet<Ident>,
builtin_macros: FxHashMap<Symbol, BuiltinMacroState>,
@@ -1046,6 +1045,9 @@ pub struct Resolver<'a> {
lifetime_elision_allowed: FxHashSet<NodeId>,
effective_visibilities: EffectiveVisibilities,
+ doc_link_resolutions: FxHashMap<LocalDefId, DocLinkResMap>,
+ doc_link_traits_in_scope: FxHashMap<LocalDefId, Vec<DefId>>,
+ all_macro_rules: FxHashMap<Symbol, Res>,
}
/// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1109,42 +1111,25 @@ impl<'a> ResolverArenas<'a> {
}
}
-impl<'a> AsMut<Resolver<'a>> for Resolver<'a> {
- fn as_mut(&mut self) -> &mut Resolver<'a> {
+impl<'a, 'tcx> AsMut<Resolver<'a, 'tcx>> for Resolver<'a, 'tcx> {
+ fn as_mut(&mut self) -> &mut Resolver<'a, 'tcx> {
self
}
}
-/// A minimal subset of resolver that can implemenent `DefIdTree`, sometimes
-/// required to satisfy borrow checker by avoiding borrowing the whole resolver.
-#[derive(Clone, Copy)]
-struct ResolverTree<'a>(&'a Untracked);
-
-impl DefIdTree for ResolverTree<'_> {
- #[inline]
- fn opt_parent(self, id: DefId) -> Option<DefId> {
- let ResolverTree(Untracked { definitions, cstore, .. }) = self;
- match id.as_local() {
- Some(id) => definitions.read().def_key(id).parent,
- None => cstore.as_any().downcast_ref::<CStore>().unwrap().def_key(id).parent,
- }
- .map(|index| DefId { index, ..id })
- }
-}
-
-impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
+impl<'a, 'b, 'tcx> DefIdTree for &'a Resolver<'b, 'tcx> {
#[inline]
fn opt_parent(self, id: DefId) -> Option<DefId> {
- ResolverTree(&self.untracked).opt_parent(id)
+ self.tcx.opt_parent(id)
}
}
-impl<'a> Resolver<'a> {
+impl<'tcx> Resolver<'_, 'tcx> {
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
self.node_id_to_def_id.get(&node).copied()
}
- pub fn local_def_id(&self, node: NodeId) -> LocalDefId {
+ fn local_def_id(&self, node: NodeId) -> LocalDefId {
self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
}
@@ -1162,10 +1147,11 @@ impl<'a> Resolver<'a> {
"adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
node_id,
data,
- self.untracked.definitions.read().def_key(self.node_id_to_def_id[&node_id]),
+ self.tcx.definitions_untracked().def_key(self.node_id_to_def_id[&node_id]),
);
- let def_id = self.untracked.definitions.write().create_def(parent, data);
+ // FIXME: remove `def_span` body, pass in the right spans here and call `tcx.at().create_def()`
+ let def_id = self.tcx.untracked().definitions.write().create_def(parent, data);
// Create the definition.
if expn_id != ExpnId::root() {
@@ -1174,7 +1160,7 @@ impl<'a> Resolver<'a> {
// A relative span's parent must be an absolute span.
debug_assert_eq!(span.data_untracked().parent, None);
- let _id = self.untracked.source_span.push(span);
+ let _id = self.tcx.untracked().source_span.push(span);
debug_assert_eq!(_id, def_id);
// Some things for which we allocate `LocalDefId`s don't correspond to
@@ -1193,23 +1179,21 @@ impl<'a> Resolver<'a> {
if let Some(def_id) = def_id.as_local() {
self.item_generics_num_lifetimes[&def_id]
} else {
- self.cstore().item_generics_num_lifetimes(def_id, self.session)
+ self.cstore().item_generics_num_lifetimes(def_id, self.tcx.sess)
}
}
- pub fn sess(&self) -> &'a Session {
- self.session
+ pub fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
}
}
-impl<'a> Resolver<'a> {
+impl<'a, 'tcx> Resolver<'a, 'tcx> {
pub fn new(
- session: &'a Session,
+ tcx: TyCtxt<'tcx>,
krate: &Crate,
- crate_name: Symbol,
- metadata_loader: Box<MetadataLoaderDyn>,
arenas: &'a ResolverArenas<'a>,
- ) -> Resolver<'a> {
+ ) -> Resolver<'a, 'tcx> {
let root_def_id = CRATE_DEF_ID.to_def_id();
let mut module_map = FxHashMap::default();
let graph_root = arenas.new_module(
@@ -1217,7 +1201,7 @@ impl<'a> Resolver<'a> {
ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty),
ExpnId::root(),
krate.spans.inner_span,
- session.contains_name(&krate.attrs, sym::no_implicit_prelude),
+ tcx.sess.contains_name(&krate.attrs, sym::no_implicit_prelude),
&mut module_map,
);
let empty_module = arenas.new_module(
@@ -1229,8 +1213,6 @@ impl<'a> Resolver<'a> {
&mut FxHashMap::default(),
);
- let definitions = Definitions::new(session.local_stable_crate_id());
-
let mut visibilities = FxHashMap::default();
visibilities.insert(CRATE_DEF_ID, ty::Visibility::Public);
@@ -1242,11 +1224,8 @@ impl<'a> Resolver<'a> {
let mut invocation_parents = FxHashMap::default();
invocation_parents.insert(LocalExpnId::ROOT, (CRATE_DEF_ID, ImplTraitContext::Existential));
- let mut source_span = IndexVec::default();
- let _id = source_span.push(krate.spans.inner_span);
- debug_assert_eq!(_id, CRATE_DEF_ID);
-
- let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> = session
+ let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> = tcx
+ .sess
.opts
.externs
.iter()
@@ -1254,19 +1233,19 @@ impl<'a> Resolver<'a> {
.map(|(name, _)| (Ident::from_str(name), Default::default()))
.collect();
- if !session.contains_name(&krate.attrs, sym::no_core) {
+ if !tcx.sess.contains_name(&krate.attrs, sym::no_core) {
extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default());
- if !session.contains_name(&krate.attrs, sym::no_std) {
+ if !tcx.sess.contains_name(&krate.attrs, sym::no_std) {
extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default());
}
}
- let registered_tools = macros::registered_tools(session, &krate.attrs);
+ let registered_tools = macros::registered_tools(tcx.sess, &krate.attrs);
- let features = session.features_untracked();
+ let features = tcx.sess.features_untracked();
let mut resolver = Resolver {
- session,
+ tcx,
expn_that_defined: Default::default(),
@@ -1304,7 +1283,6 @@ impl<'a> Resolver<'a> {
has_pub_restricted: false,
used_imports: FxHashSet::default(),
maybe_unused_trait_imports: Default::default(),
- maybe_unused_extern_crates: Vec::new(),
privacy_errors: Vec::new(),
ambiguity_errors: Vec::new(),
@@ -1320,23 +1298,16 @@ impl<'a> Resolver<'a> {
vis: ty::Visibility::Public,
}),
- metadata_loader,
- local_crate_name: crate_name,
used_extern_options: Default::default(),
- untracked: Untracked {
- cstore: Box::new(CStore::new(session)),
- source_span,
- definitions: RwLock::new(definitions),
- },
macro_names: FxHashSet::default(),
builtin_macros: Default::default(),
builtin_macro_kinds: Default::default(),
registered_tools,
macro_use_prelude: FxHashMap::default(),
macro_map: FxHashMap::default(),
- dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(session.edition())),
- dummy_ext_derive: Lrc::new(SyntaxExtension::dummy_derive(session.edition())),
- non_macro_attr: Lrc::new(SyntaxExtension::non_macro_attr(session.edition())),
+ dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(tcx.sess.edition())),
+ dummy_ext_derive: Lrc::new(SyntaxExtension::dummy_derive(tcx.sess.edition())),
+ non_macro_attr: Lrc::new(SyntaxExtension::non_macro_attr(tcx.sess.edition())),
invocation_parent_scopes: Default::default(),
output_macro_rules_scopes: Default::default(),
macro_rules_scopes: Default::default(),
@@ -1374,6 +1345,9 @@ impl<'a> Resolver<'a> {
confused_type_with_std_module: Default::default(),
lifetime_elision_allowed: Default::default(),
effective_visibilities: Default::default(),
+ doc_link_resolutions: Default::default(),
+ doc_link_traits_in_scope: Default::default(),
+ all_macro_rules: Default::default(),
};
let root_parent_scope = ParentScope::module(graph_root, &resolver);
@@ -1394,14 +1368,14 @@ impl<'a> Resolver<'a> {
self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude, module_map)
}
- pub fn next_node_id(&mut self) -> NodeId {
+ fn next_node_id(&mut self) -> NodeId {
let start = self.next_node_id;
let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
self.next_node_id = ast::NodeId::from_u32(next);
start
}
- pub fn next_node_ids(&mut self, count: usize) -> std::ops::Range<NodeId> {
+ fn next_node_ids(&mut self, count: usize) -> std::ops::Range<NodeId> {
let start = self.next_node_id;
let end = start.as_usize().checked_add(count).expect("input too large; ran out of NodeIds");
self.next_node_id = ast::NodeId::from_usize(end);
@@ -1424,12 +1398,10 @@ impl<'a> Resolver<'a> {
let extern_crate_map = self.extern_crate_map;
let reexport_map = self.reexport_map;
let maybe_unused_trait_imports = self.maybe_unused_trait_imports;
- let maybe_unused_extern_crates = self.maybe_unused_extern_crates;
let glob_map = self.glob_map;
let main_def = self.main_def;
let confused_type_with_std_module = self.confused_type_with_std_module;
let effective_visibilities = self.effective_visibilities;
- let untracked = self.untracked;
let global_ctxt = ResolverGlobalCtxt {
expn_that_defined,
visibilities,
@@ -1439,17 +1411,14 @@ impl<'a> Resolver<'a> {
reexport_map,
glob_map,
maybe_unused_trait_imports,
- maybe_unused_extern_crates,
- extern_prelude: self
- .extern_prelude
- .iter()
- .map(|(ident, entry)| (ident.name, entry.introduced_by_item))
- .collect(),
main_def,
trait_impls: self.trait_impls,
proc_macros,
confused_type_with_std_module,
registered_tools: self.registered_tools,
+ doc_link_resolutions: self.doc_link_resolutions,
+ doc_link_traits_in_scope: self.doc_link_traits_in_scope,
+ all_macro_rules: self.all_macro_rules,
};
let ast_lowering = ty::ResolverAstLowering {
legacy_const_generic_args: self.legacy_const_generic_args,
@@ -1465,70 +1434,21 @@ impl<'a> Resolver<'a> {
builtin_macro_kinds: self.builtin_macro_kinds,
lifetime_elision_allowed: self.lifetime_elision_allowed,
};
- ResolverOutputs { global_ctxt, ast_lowering, untracked }
- }
-
- pub fn clone_outputs(&self) -> ResolverOutputs {
- let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
- let definitions = self.untracked.definitions.clone();
- let cstore = Box::new(self.cstore().clone());
- let untracked =
- Untracked { cstore, source_span: self.untracked.source_span.clone(), definitions };
- let global_ctxt = ResolverGlobalCtxt {
- expn_that_defined: self.expn_that_defined.clone(),
- visibilities: self.visibilities.clone(),
- has_pub_restricted: self.has_pub_restricted,
- extern_crate_map: self.extern_crate_map.clone(),
- reexport_map: self.reexport_map.clone(),
- glob_map: self.glob_map.clone(),
- maybe_unused_trait_imports: self.maybe_unused_trait_imports.clone(),
- maybe_unused_extern_crates: self.maybe_unused_extern_crates.clone(),
- extern_prelude: self
- .extern_prelude
- .iter()
- .map(|(ident, entry)| (ident.name, entry.introduced_by_item))
- .collect(),
- main_def: self.main_def,
- trait_impls: self.trait_impls.clone(),
- proc_macros,
- confused_type_with_std_module: self.confused_type_with_std_module.clone(),
- registered_tools: self.registered_tools.clone(),
- effective_visibilities: self.effective_visibilities.clone(),
- };
- let ast_lowering = ty::ResolverAstLowering {
- legacy_const_generic_args: self.legacy_const_generic_args.clone(),
- partial_res_map: self.partial_res_map.clone(),
- import_res_map: self.import_res_map.clone(),
- label_res_map: self.label_res_map.clone(),
- lifetimes_res_map: self.lifetimes_res_map.clone(),
- extra_lifetime_params_map: self.extra_lifetime_params_map.clone(),
- next_node_id: self.next_node_id,
- node_id_to_def_id: self.node_id_to_def_id.clone(),
- def_id_to_node_id: self.def_id_to_node_id.clone(),
- trait_map: self.trait_map.clone(),
- builtin_macro_kinds: self.builtin_macro_kinds.clone(),
- lifetime_elision_allowed: self.lifetime_elision_allowed.clone(),
- };
- ResolverOutputs { global_ctxt, ast_lowering, untracked }
+ ResolverOutputs { global_ctxt, ast_lowering }
}
fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
- StableHashingContext::new(self.session, &self.untracked)
+ StableHashingContext::new(self.tcx.sess, self.tcx.untracked())
}
- pub fn crate_loader(&mut self) -> CrateLoader<'_> {
- CrateLoader::new(
- &self.session,
- &*self.metadata_loader,
- self.local_crate_name,
- &mut *self.untracked.cstore.untracked_as_any().downcast_mut().unwrap(),
- self.untracked.definitions.read(),
- &mut self.used_extern_options,
- )
+ fn crate_loader<T>(&mut self, f: impl FnOnce(&mut CrateLoader<'_, '_>) -> T) -> T {
+ let mut cstore = self.tcx.untracked().cstore.write();
+ let cstore = cstore.untracked_as_any().downcast_mut().unwrap();
+ f(&mut CrateLoader::new(self.tcx, &mut *cstore, &mut self.used_extern_options))
}
- pub fn cstore(&self) -> &CStore {
- self.untracked.cstore.as_any().downcast_ref().unwrap()
+ fn cstore(&self) -> MappedReadGuard<'_, CStore> {
+ CStore::from_tcx(self.tcx)
}
fn dummy_ext(&self, macro_kind: MacroKind) -> Lrc<SyntaxExtension> {
@@ -1561,21 +1481,26 @@ impl<'a> Resolver<'a> {
/// Entry point to crate resolution.
pub fn resolve_crate(&mut self, krate: &Crate) {
- self.session.time("resolve_crate", || {
- self.session.time("finalize_imports", || ImportResolver { r: self }.finalize_imports());
- self.session.time("compute_effective_visibilities", || {
+ self.tcx.sess.time("resolve_crate", || {
+ self.tcx.sess.time("finalize_imports", || self.finalize_imports());
+ self.tcx.sess.time("compute_effective_visibilities", || {
EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate)
});
- self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
- self.session.time("late_resolve_crate", || self.late_resolve_crate(krate));
- self.session.time("resolve_main", || self.resolve_main());
- self.session.time("resolve_check_unused", || self.check_unused(krate));
- self.session.time("resolve_report_errors", || self.report_errors(krate));
- self.session.time("resolve_postprocess", || self.crate_loader().postprocess(krate));
+ self.tcx.sess.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
+ self.tcx.sess.time("late_resolve_crate", || self.late_resolve_crate(krate));
+ self.tcx.sess.time("resolve_main", || self.resolve_main());
+ self.tcx.sess.time("resolve_check_unused", || self.check_unused(krate));
+ self.tcx.sess.time("resolve_report_errors", || self.report_errors(krate));
+ self.tcx
+ .sess
+ .time("resolve_postprocess", || self.crate_loader(|c| c.postprocess(krate)));
});
+
+ // Make sure we don't mutate the cstore from here on.
+ self.tcx.untracked().cstore.leak();
}
- pub fn traits_in_scope(
+ fn traits_in_scope(
&mut self,
current_trait: Option<Module<'a>>,
parent_scope: &ParentScope<'a>,
@@ -1911,10 +1836,10 @@ impl<'a> Resolver<'a> {
} else {
let crate_id = if finalize {
let Some(crate_id) =
- self.crate_loader().process_path_extern(ident.name, ident.span) else { return Some(self.dummy_binding); };
+ self.crate_loader(|c| c.process_path_extern(ident.name, ident.span)) else { return Some(self.dummy_binding); };
crate_id
} else {
- self.crate_loader().maybe_process_path_extern(ident.name)?
+ self.crate_loader(|c| c.maybe_process_path_extern(ident.name))?
};
let crate_root = self.expect_module(crate_id.as_def_id());
let vis = ty::Visibility::<LocalDefId>::Public;
@@ -1927,7 +1852,7 @@ impl<'a> Resolver<'a> {
/// isn't something that can be returned because it can't be made to live that long,
/// and also it's a private type. Fortunately rustdoc doesn't need to know the error,
/// just that an error occurred.
- pub fn resolve_rustdoc_path(
+ fn resolve_rustdoc_path(
&mut self,
path_str: &str,
ns: Namespace,
@@ -1959,41 +1884,17 @@ impl<'a> Resolver<'a> {
}
}
- /// For rustdoc.
- /// For local modules returns only reexports, for external modules returns all children.
- pub fn module_children_or_reexports(&self, def_id: DefId) -> Vec<ModChild> {
- if let Some(def_id) = def_id.as_local() {
- self.reexport_map.get(&def_id).cloned().unwrap_or_default()
- } else {
- self.cstore().module_children_untracked(def_id, self.session).collect()
- }
- }
-
- /// For rustdoc.
- pub fn macro_rules_scope(&self, def_id: LocalDefId) -> (MacroRulesScopeRef<'a>, Res) {
- let scope = *self.macro_rules_scopes.get(&def_id).expect("not a `macro_rules` item");
- match scope.get() {
- MacroRulesScope::Binding(mb) => (scope, mb.binding.res()),
- _ => unreachable!(),
- }
- }
-
- /// For rustdoc.
- pub fn get_partial_res(&self, node_id: NodeId) -> Option<PartialRes> {
- self.partial_res_map.get(&node_id).copied()
- }
-
/// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
#[inline]
- pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
- def_id.as_local().map(|def_id| self.untracked.source_span[def_id])
+ fn opt_span(&self, def_id: DefId) -> Option<Span> {
+ def_id.as_local().map(|def_id| self.tcx.source_span(def_id))
}
/// Retrieves the name of the given `DefId`.
#[inline]
- pub fn opt_name(&self, def_id: DefId) -> Option<Symbol> {
+ fn opt_name(&self, def_id: DefId) -> Option<Symbol> {
let def_key = match def_id.as_local() {
- Some(def_id) => self.untracked.definitions.read().def_key(def_id),
+ Some(def_id) => self.tcx.definitions_untracked().def_key(def_id),
None => self.cstore().def_key(def_id),
};
def_key.get_opt_name()
@@ -2002,7 +1903,7 @@ impl<'a> Resolver<'a> {
/// Checks if an expression refers to a function marked with
/// `#[rustc_legacy_const_generics]` and returns the argument index list
/// from the attribute.
- pub fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>> {
+ fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>> {
if let ExprKind::Path(None, path) = &expr.kind {
// Don't perform legacy const generics rewriting if the path already
// has generic arguments.
@@ -2025,7 +1926,7 @@ impl<'a> Resolver<'a> {
let attr = self
.cstore()
- .item_attrs_untracked(def_id, self.session)
+ .item_attrs_untracked(def_id, self.tcx.sess)
.find(|a| a.has_name(sym::rustc_legacy_const_generics))?;
let mut ret = Vec::new();
for meta in attr.meta_item_list()? {
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index b5b1602c5..b38c11e8b 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -1,7 +1,6 @@
//! A bunch of methods and structures more or less related to resolving macros and
//! interface provided by `Resolver` to macro expander.
-use crate::imports::ImportResolver;
use crate::Namespace::*;
use crate::{BuiltinMacroState, Determinacy};
use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
@@ -39,7 +38,7 @@ type Res = def::Res<NodeId>;
/// Binding produced by a `macro_rules` item.
/// Not modularized, can shadow previous `macro_rules` bindings, etc.
#[derive(Debug)]
-pub struct MacroRulesBinding<'a> {
+pub(crate) struct MacroRulesBinding<'a> {
pub(crate) binding: &'a NameBinding<'a>,
/// `macro_rules` scope into which the `macro_rules` item was planted.
pub(crate) parent_macro_rules_scope: MacroRulesScopeRef<'a>,
@@ -52,7 +51,7 @@ pub struct MacroRulesBinding<'a> {
/// Some macro invocations need to introduce `macro_rules` scopes too because they
/// can potentially expand into macro definitions.
#[derive(Copy, Clone, Debug)]
-pub enum MacroRulesScope<'a> {
+pub(crate) enum MacroRulesScope<'a> {
/// Empty "root" scope at the crate start containing no names.
Empty,
/// The scope introduced by a `macro_rules!` macro definition.
@@ -160,7 +159,7 @@ fn soft_custom_inner_attributes_gate(path: &ast::Path, invoc: &Invocation) -> bo
false
}
-impl<'a> ResolverExpand for Resolver<'a> {
+impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
fn next_node_id(&mut self) -> NodeId {
self.next_node_id()
}
@@ -195,7 +194,8 @@ impl<'a> ResolverExpand for Resolver<'a> {
fn register_builtin_macro(&mut self, name: Symbol, ext: SyntaxExtensionKind) {
if self.builtin_macros.insert(name, BuiltinMacroState::NotYetSeen(ext)).is_some() {
- self.session
+ self.tcx
+ .sess
.diagnostic()
.bug(&format!("built-in macro `{}` was already registered", name));
}
@@ -216,7 +216,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
ExpnData::allow_unstable(
ExpnKind::AstPass(pass),
call_site,
- self.session.edition(),
+ self.tcx.sess.edition(),
features.into(),
None,
parent_module,
@@ -232,7 +232,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
}
fn resolve_imports(&mut self) {
- ImportResolver { r: self }.resolve_imports()
+ self.resolve_imports()
}
fn resolve_macro_invocation(
@@ -430,7 +430,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
PathResult::NonModule(..) |
// HACK(Urgau): This shouldn't be necessary
PathResult::Failed { is_error_from_last_segment: false, .. } => {
- self.session
+ self.tcx.sess
.struct_span_err(span, "not sure whether the path is accessible or not")
.note("the type may have associated items, but we are currently not checking them")
.emit();
@@ -455,7 +455,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
}
fn get_proc_macro_quoted_span(&self, krate: CrateNum, id: usize) -> Span {
- self.cstore().get_proc_macro_quoted_span_untracked(krate, id, self.session)
+ self.cstore().get_proc_macro_quoted_span_untracked(krate, id, self.tcx.sess)
}
fn declare_proc_macro(&mut self, id: NodeId) {
@@ -467,7 +467,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
}
}
-impl<'a> Resolver<'a> {
+impl<'a, 'tcx> Resolver<'a, 'tcx> {
/// Resolve macro path with error reporting and recovery.
/// Uses dummy syntax extensions for unresolved macros or macros with unexpected resolutions
/// for better error recovery.
@@ -493,10 +493,10 @@ impl<'a> Resolver<'a> {
// Report errors for the resolved macro.
for segment in &path.segments {
if let Some(args) = &segment.args {
- self.session.span_err(args.span(), "generic arguments in macro path");
+ self.tcx.sess.span_err(args.span(), "generic arguments in macro path");
}
if kind == MacroKind::Attr && segment.ident.as_str().starts_with("rustc") {
- self.session.span_err(
+ self.tcx.sess.span_err(
segment.ident.span,
"attributes starting with `rustc` are reserved for use by the `rustc` compiler",
);
@@ -508,7 +508,7 @@ impl<'a> Resolver<'a> {
if let Some(def_id) = def_id.as_local() {
self.unused_macros.remove(&def_id);
if self.proc_macro_stubs.contains(&def_id) {
- self.session.span_err(
+ self.tcx.sess.span_err(
path.span,
"can't use a procedural macro from the same crate that defines it",
);
@@ -540,7 +540,8 @@ impl<'a> Resolver<'a> {
if let Some((article, expected)) = unexpected_res {
let path_str = pprust::path_to_string(path);
let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path_str);
- self.session
+ self.tcx
+ .sess
.struct_span_err(path.span, &msg)
.span_label(path.span, format!("not {} {}", article, expected))
.emit();
@@ -550,7 +551,7 @@ impl<'a> Resolver<'a> {
// We are trying to avoid reporting this error if other related errors were reported.
if res != Res::Err
&& inner_attr
- && !self.session.features_untracked().custom_inner_attributes
+ && !self.tcx.sess.features_untracked().custom_inner_attributes
{
let msg = match res {
Res::Def(..) => "inner macro attributes are unstable",
@@ -558,17 +559,22 @@ impl<'a> Resolver<'a> {
_ => unreachable!(),
};
if soft_custom_inner_attributes_gate {
- self.session.parse_sess.buffer_lint(SOFT_UNSTABLE, path.span, node_id, msg);
+ self.tcx.sess.parse_sess.buffer_lint(SOFT_UNSTABLE, path.span, node_id, msg);
} else {
- feature_err(&self.session.parse_sess, sym::custom_inner_attributes, path.span, msg)
- .emit();
+ feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::custom_inner_attributes,
+ path.span,
+ msg,
+ )
+ .emit();
}
}
Ok((ext, res))
}
- pub fn resolve_macro_path(
+ pub(crate) fn resolve_macro_path(
&mut self,
path: &ast::Path,
kind: Option<MacroKind>,
@@ -655,7 +661,7 @@ impl<'a> Resolver<'a> {
// Make sure compilation does not succeed if preferred macro resolution
// has changed after the macro had been expanded. In theory all such
// situations should be reported as errors, so this is a bug.
- this.session.delay_span_bug(span, "inconsistent resolution for a macro");
+ this.tcx.sess.delay_span_bug(span, "inconsistent resolution for a macro");
}
} else {
// It's possible that the macro was unresolved (indeterminate) and silently
@@ -672,7 +678,7 @@ impl<'a> Resolver<'a> {
Segment::names_to_string(path)
);
let msg_note = "import resolution is stuck, try simplifying macro imports";
- this.session.struct_span_err(span, &msg).note(msg_note).emit();
+ this.tcx.sess.struct_span_err(span, &msg).note(msg_note).emit();
}
}
};
@@ -699,7 +705,7 @@ impl<'a> Resolver<'a> {
// try to suggest if it's not a macro, maybe a function
if let PathResult::NonModule(partial_res) = self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope)
&& partial_res.unresolved_segments() == 0 {
- let sm = self.session.source_map();
+ let sm = self.tcx.sess.source_map();
let exclamation_span = sm.next_point(span);
suggestion = Some((
vec![(exclamation_span, "".to_string())],
@@ -762,7 +768,7 @@ impl<'a> Resolver<'a> {
Err(..) => {
let expected = kind.descr_expected();
let msg = format!("cannot find {} `{}` in this scope", expected, ident);
- let mut err = self.session.struct_span_err(ident.span, &msg);
+ let mut err = self.tcx.sess.struct_span_err(ident.span, &msg);
self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident);
err.emit();
}
@@ -804,7 +810,7 @@ impl<'a> Resolver<'a> {
let soft_handler =
|lint, span, msg: &_| lint_buffer.buffer_lint(lint, node_id, span, msg);
stability::report_unstable(
- self.session,
+ self.tcx.sess,
feature,
reason.to_opt_reason(),
issue,
@@ -840,7 +846,7 @@ impl<'a> Resolver<'a> {
if kind != NonMacroAttrKind::Tool && binding.map_or(true, |b| b.is_import()) {
let msg =
format!("cannot use {} {} through an import", kind.article(), kind.descr());
- let mut err = self.session.struct_span_err(span, &msg);
+ let mut err = self.tcx.sess.struct_span_err(span, &msg);
if let Some(binding) = binding {
err.span_note(binding.span, &format!("the {} imported here", kind.descr()));
}
@@ -855,7 +861,7 @@ impl<'a> Resolver<'a> {
if ident.name == sym::cfg || ident.name == sym::cfg_attr {
let macro_kind = self.get_macro(res).map(|macro_data| macro_data.ext.macro_kind());
if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) {
- self.session.span_err(
+ self.tcx.sess.span_err(
ident.span,
&format!("name `{}` is reserved in attribute namespace", ident),
);
@@ -871,12 +877,7 @@ impl<'a> Resolver<'a> {
item: &ast::Item,
edition: Edition,
) -> (SyntaxExtension, Vec<(usize, Span)>) {
- let (mut result, mut rule_spans) = compile_declarative_macro(
- &self.session,
- self.session.features_untracked(),
- item,
- edition,
- );
+ let (mut result, mut rule_spans) = compile_declarative_macro(self.tcx.sess, item, edition);
if let Some(builtin_name) = result.builtin_name {
// The macro was marked with `#[rustc_builtin_macro]`.
@@ -895,7 +896,7 @@ impl<'a> Resolver<'a> {
}
BuiltinMacroState::AlreadySeen(span) => {
struct_span_err!(
- self.session,
+ self.tcx.sess,
item.span,
E0773,
"attempted to define built-in macro more than once"
@@ -906,7 +907,7 @@ impl<'a> Resolver<'a> {
}
} else {
let msg = format!("cannot find a built-in macro with name `{}`", item.ident);
- self.session.span_err(item.span, &msg);
+ self.tcx.sess.span_err(item.span, &msg);
}
}
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
new file mode 100644
index 000000000..b8853c174
--- /dev/null
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -0,0 +1,388 @@
+use pulldown_cmark::{BrokenLink, Event, LinkType, Options, Parser, Tag};
+use rustc_ast as ast;
+use rustc_ast::util::comments::beautify_doc_string;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_span::def_id::DefId;
+use rustc_span::symbol::{kw, Symbol};
+use rustc_span::Span;
+use std::{cmp, mem};
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum DocFragmentKind {
+ /// A doc fragment created from a `///` or `//!` doc comment.
+ SugaredDoc,
+ /// A doc fragment created from a "raw" `#[doc=""]` attribute.
+ RawDoc,
+}
+
+/// A portion of documentation, extracted from a `#[doc]` attribute.
+///
+/// Each variant contains the line number within the complete doc-comment where the fragment
+/// starts, as well as the Span where the corresponding doc comment or attribute is located.
+///
+/// Included files are kept separate from inline doc comments so that proper line-number
+/// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are
+/// kept separate because of issue #42760.
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct DocFragment {
+ pub span: Span,
+ /// The module this doc-comment came from.
+ ///
+ /// This allows distinguishing between the original documentation and a pub re-export.
+ /// If it is `None`, the item was not re-exported.
+ pub parent_module: Option<DefId>,
+ pub doc: Symbol,
+ pub kind: DocFragmentKind,
+ pub indent: usize,
+}
+
+#[derive(Clone, Copy, Debug)]
+pub enum MalformedGenerics {
+ /// This link has unbalanced angle brackets.
+ ///
+ /// For example, `Vec<T` should trigger this, as should `Vec<T>>`.
+ UnbalancedAngleBrackets,
+ /// The generics are not attached to a type.
+ ///
+ /// For example, `<T>` should trigger this.
+ ///
+ /// This is detected by checking if the path is empty after the generics are stripped.
+ MissingType,
+ /// The link uses fully-qualified syntax, which is currently unsupported.
+ ///
+ /// For example, `<Vec as IntoIterator>::into_iter` should trigger this.
+ ///
+ /// This is detected by checking if ` as ` (the keyword `as` with spaces around it) is inside
+ /// angle brackets.
+ HasFullyQualifiedSyntax,
+ /// The link has an invalid path separator.
+ ///
+ /// For example, `Vec:<T>:new()` should trigger this. Note that `Vec:new()` will **not**
+ /// trigger this because it has no generics and thus [`strip_generics_from_path`] will not be
+ /// called.
+ ///
+ /// Note that this will also **not** be triggered if the invalid path separator is inside angle
+ /// brackets because rustdoc mostly ignores what's inside angle brackets (except for
+ /// [`HasFullyQualifiedSyntax`](MalformedGenerics::HasFullyQualifiedSyntax)).
+ ///
+ /// This is detected by checking if there is a colon followed by a non-colon in the link.
+ InvalidPathSeparator,
+ /// The link has too many angle brackets.
+ ///
+ /// For example, `Vec<<T>>` should trigger this.
+ TooManyAngleBrackets,
+ /// The link has empty angle brackets.
+ ///
+ /// For example, `Vec<>` should trigger this.
+ EmptyAngleBrackets,
+}
+
+/// Removes excess indentation on comments in order for the Markdown
+/// to be parsed correctly. This is necessary because the convention for
+/// writing documentation is to provide a space between the /// or //! marker
+/// and the doc text, but Markdown is whitespace-sensitive. For example,
+/// a block of text with four-space indentation is parsed as a code block,
+/// so if we didn't unindent comments, these list items
+///
+/// /// A list:
+/// ///
+/// /// - Foo
+/// /// - Bar
+///
+/// would be parsed as if they were in a code block, which is likely not what the user intended.
+pub fn unindent_doc_fragments(docs: &mut [DocFragment]) {
+ // `add` is used in case the most common sugared doc syntax is used ("/// "). The other
+ // fragments kind's lines are never starting with a whitespace unless they are using some
+ // markdown formatting requiring it. Therefore, if the doc block have a mix between the two,
+ // we need to take into account the fact that the minimum indent minus one (to take this
+ // whitespace into account).
+ //
+ // For example:
+ //
+ // /// hello!
+ // #[doc = "another"]
+ //
+ // In this case, you want "hello! another" and not "hello! another".
+ let add = if docs.windows(2).any(|arr| arr[0].kind != arr[1].kind)
+ && docs.iter().any(|d| d.kind == DocFragmentKind::SugaredDoc)
+ {
+ // In case we have a mix of sugared doc comments and "raw" ones, we want the sugared one to
+ // "decide" how much the minimum indent will be.
+ 1
+ } else {
+ 0
+ };
+
+ // `min_indent` is used to know how much whitespaces from the start of each lines must be
+ // removed. Example:
+ //
+ // /// hello!
+ // #[doc = "another"]
+ //
+ // In here, the `min_indent` is 1 (because non-sugared fragment are always counted with minimum
+ // 1 whitespace), meaning that "hello!" will be considered a codeblock because it starts with 4
+ // (5 - 1) whitespaces.
+ let Some(min_indent) = docs
+ .iter()
+ .map(|fragment| {
+ fragment.doc.as_str().lines().fold(usize::MAX, |min_indent, line| {
+ if line.chars().all(|c| c.is_whitespace()) {
+ min_indent
+ } else {
+ // Compare against either space or tab, ignoring whether they are
+ // mixed or not.
+ let whitespace = line.chars().take_while(|c| *c == ' ' || *c == '\t').count();
+ cmp::min(min_indent, whitespace)
+ + if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add }
+ }
+ })
+ })
+ .min()
+ else {
+ return;
+ };
+
+ for fragment in docs {
+ if fragment.doc == kw::Empty {
+ continue;
+ }
+
+ let min_indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 {
+ min_indent - add
+ } else {
+ min_indent
+ };
+
+ fragment.indent = min_indent;
+ }
+}
+
+/// The goal of this function is to apply the `DocFragment` transformation that is required when
+/// transforming into the final Markdown, which is applying the computed indent to each line in
+/// each doc fragment (a `DocFragment` can contain multiple lines in case of `#[doc = ""]`).
+///
+/// Note: remove the trailing newline where appropriate
+pub fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
+ let s = frag.doc.as_str();
+ let mut iter = s.lines();
+ if s.is_empty() {
+ out.push('\n');
+ return;
+ }
+ while let Some(line) = iter.next() {
+ if line.chars().any(|c| !c.is_whitespace()) {
+ assert!(line.len() >= frag.indent);
+ out.push_str(&line[frag.indent..]);
+ } else {
+ out.push_str(line);
+ }
+ out.push('\n');
+ }
+}
+
+pub fn attrs_to_doc_fragments<'a>(
+ attrs: impl Iterator<Item = (&'a ast::Attribute, Option<DefId>)>,
+ doc_only: bool,
+) -> (Vec<DocFragment>, ast::AttrVec) {
+ let mut doc_fragments = Vec::new();
+ let mut other_attrs = ast::AttrVec::new();
+ for (attr, parent_module) in attrs {
+ if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() {
+ let doc = beautify_doc_string(doc_str, comment_kind);
+ let kind = if attr.is_doc_comment() {
+ DocFragmentKind::SugaredDoc
+ } else {
+ DocFragmentKind::RawDoc
+ };
+ let fragment = DocFragment { span: attr.span, doc, kind, parent_module, indent: 0 };
+ doc_fragments.push(fragment);
+ } else if !doc_only {
+ other_attrs.push(attr.clone());
+ }
+ }
+
+ unindent_doc_fragments(&mut doc_fragments);
+
+ (doc_fragments, other_attrs)
+}
+
+/// Return the doc-comments on this item, grouped by the module they came from.
+/// The module can be different if this is a re-export with added documentation.
+///
+/// The last newline is not trimmed so the produced strings are reusable between
+/// early and late doc link resolution regardless of their position.
+pub fn prepare_to_doc_link_resolution(
+ doc_fragments: &[DocFragment],
+) -> FxHashMap<Option<DefId>, String> {
+ let mut res = FxHashMap::default();
+ for fragment in doc_fragments {
+ let out_str = res.entry(fragment.parent_module).or_default();
+ add_doc_fragment(out_str, fragment);
+ }
+ res
+}
+
+/// Options for rendering Markdown in the main body of documentation.
+pub fn main_body_opts() -> Options {
+ Options::ENABLE_TABLES
+ | Options::ENABLE_FOOTNOTES
+ | Options::ENABLE_STRIKETHROUGH
+ | Options::ENABLE_TASKLISTS
+ | Options::ENABLE_SMART_PUNCTUATION
+}
+
+fn strip_generics_from_path_segment(segment: Vec<char>) -> Result<String, MalformedGenerics> {
+ let mut stripped_segment = String::new();
+ let mut param_depth = 0;
+
+ let mut latest_generics_chunk = String::new();
+
+ for c in segment {
+ if c == '<' {
+ param_depth += 1;
+ latest_generics_chunk.clear();
+ } else if c == '>' {
+ param_depth -= 1;
+ if latest_generics_chunk.contains(" as ") {
+ // The segment tries to use fully-qualified syntax, which is currently unsupported.
+ // Give a helpful error message instead of completely ignoring the angle brackets.
+ return Err(MalformedGenerics::HasFullyQualifiedSyntax);
+ }
+ } else {
+ if param_depth == 0 {
+ stripped_segment.push(c);
+ } else {
+ latest_generics_chunk.push(c);
+ }
+ }
+ }
+
+ if param_depth == 0 {
+ Ok(stripped_segment)
+ } else {
+ // The segment has unbalanced angle brackets, e.g. `Vec<T` or `Vec<T>>`
+ Err(MalformedGenerics::UnbalancedAngleBrackets)
+ }
+}
+
+pub fn strip_generics_from_path(path_str: &str) -> Result<Box<str>, MalformedGenerics> {
+ if !path_str.contains(['<', '>']) {
+ return Ok(path_str.into());
+ }
+ let mut stripped_segments = vec![];
+ let mut path = path_str.chars().peekable();
+ let mut segment = Vec::new();
+
+ while let Some(chr) = path.next() {
+ match chr {
+ ':' => {
+ if path.next_if_eq(&':').is_some() {
+ let stripped_segment =
+ strip_generics_from_path_segment(mem::take(&mut segment))?;
+ if !stripped_segment.is_empty() {
+ stripped_segments.push(stripped_segment);
+ }
+ } else {
+ return Err(MalformedGenerics::InvalidPathSeparator);
+ }
+ }
+ '<' => {
+ segment.push(chr);
+
+ match path.next() {
+ Some('<') => {
+ return Err(MalformedGenerics::TooManyAngleBrackets);
+ }
+ Some('>') => {
+ return Err(MalformedGenerics::EmptyAngleBrackets);
+ }
+ Some(chr) => {
+ segment.push(chr);
+
+ while let Some(chr) = path.next_if(|c| *c != '>') {
+ segment.push(chr);
+ }
+ }
+ None => break,
+ }
+ }
+ _ => segment.push(chr),
+ }
+ trace!("raw segment: {:?}", segment);
+ }
+
+ if !segment.is_empty() {
+ let stripped_segment = strip_generics_from_path_segment(segment)?;
+ if !stripped_segment.is_empty() {
+ stripped_segments.push(stripped_segment);
+ }
+ }
+
+ debug!("path_str: {:?}\nstripped segments: {:?}", path_str, &stripped_segments);
+
+ let stripped_path = stripped_segments.join("::");
+
+ if !stripped_path.is_empty() {
+ Ok(stripped_path.into())
+ } else {
+ Err(MalformedGenerics::MissingType)
+ }
+}
+
+/// Returns whether the first doc-comment is an inner attribute.
+///
+//// If there are no doc-comments, return true.
+/// FIXME(#78591): Support both inner and outer attributes on the same item.
+pub fn inner_docs(attrs: &[ast::Attribute]) -> bool {
+ attrs.iter().find(|a| a.doc_str().is_some()).map_or(true, |a| a.style == ast::AttrStyle::Inner)
+}
+
+/// Simplified version of the corresponding function in rustdoc.
+/// If the rustdoc version returns a successful result, this function must return the same result.
+/// Otherwise this function may return anything.
+fn preprocess_link(link: &str) -> Box<str> {
+ let link = link.replace('`', "");
+ let link = link.split('#').next().unwrap();
+ let link = link.trim();
+ let link = link.rsplit('@').next().unwrap();
+ let link = link.strip_suffix("()").unwrap_or(link);
+ let link = link.strip_suffix("{}").unwrap_or(link);
+ let link = link.strip_suffix("[]").unwrap_or(link);
+ let link = if link != "!" { link.strip_suffix('!').unwrap_or(link) } else { link };
+ strip_generics_from_path(link).unwrap_or_else(|_| link.into())
+}
+
+/// Keep inline and reference links `[]`,
+/// but skip autolinks `<>` which we never consider to be intra-doc links.
+pub fn may_be_doc_link(link_type: LinkType) -> bool {
+ match link_type {
+ LinkType::Inline
+ | LinkType::Reference
+ | LinkType::ReferenceUnknown
+ | LinkType::Collapsed
+ | LinkType::CollapsedUnknown
+ | LinkType::Shortcut
+ | LinkType::ShortcutUnknown => true,
+ LinkType::Autolink | LinkType::Email => false,
+ }
+}
+
+/// Simplified version of `preprocessed_markdown_links` from rustdoc.
+/// Must return at least the same links as it, but may add some more links on top of that.
+pub(crate) fn attrs_to_preprocessed_links(attrs: &[ast::Attribute]) -> Vec<Box<str>> {
+ let (doc_fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true);
+ let doc = prepare_to_doc_link_resolution(&doc_fragments).into_values().next().unwrap();
+
+ Parser::new_with_broken_link_callback(
+ &doc,
+ main_body_opts(),
+ Some(&mut |link: BrokenLink<'_>| Some((link.reference, "".into()))),
+ )
+ .filter_map(|event| match event {
+ Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
+ Some(preprocess_link(&dest))
+ }
+ _ => None,
+ })
+ .collect()
+}