diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:43 +0000 |
commit | 3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245 (patch) | |
tree | daf049b282ab10e8c3d03e409b3cd84ff3f7690c /compiler/rustc_resolve | |
parent | Adding debian version 1.68.2+dfsg1-1. (diff) | |
download | rustc-3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245.tar.xz rustc-3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245.zip |
Merging upstream version 1.69.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_resolve')
-rw-r--r-- | compiler/rustc_resolve/Cargo.toml | 3 | ||||
-rw-r--r-- | compiler/rustc_resolve/locales/en-US.ftl | 211 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/build_reduced_graph.rs | 126 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/check_unused.rs | 145 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/def_collector.rs | 10 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/diagnostics.rs | 226 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/effective_visibilities.rs | 42 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/errors.rs | 14 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/ident.rs | 23 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/imports.rs | 163 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/late.rs | 265 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/late/diagnostics.rs | 142 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/lib.rs | 309 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/macros.rs | 69 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/rustdoc.rs | 388 |
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, ¬e_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() +} |