Auto merge of #135896 - matthiaskrgr:rollup-g6rv7za, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #132983 (Edit dangling pointers ) - #135409 (Fix ICE-133117: multiple never-pattern arm doesn't have false_edge_start_block) - #135557 (Point at invalid utf-8 span on user's source code) - #135596 (Properly note when query stack is being cut off) - #135794 (Detect missing fields with default values and suggest `..`) - #135814 (ci: use ghcr buildkit image) - #135826 (Misc. `rustc_resolve` cleanups) - #135837 (Remove test panic from File::open) - #135856 (Library: Finalize dyn compatibility renaming) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
a30f9151fe
55 changed files with 1081 additions and 684 deletions
|
@ -16,6 +16,7 @@
|
|||
#![feature(proc_macro_internals)]
|
||||
#![feature(proc_macro_quote)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(string_from_utf8_lossy_owned)]
|
||||
#![feature(try_blocks)]
|
||||
#![warn(unreachable_pub)]
|
||||
// tidy-alphabetical-end
|
||||
|
|
|
@ -13,7 +13,7 @@ use rustc_expand::base::{
|
|||
use rustc_expand::module::DirOwnership;
|
||||
use rustc_lint_defs::BuiltinLintDiag;
|
||||
use rustc_parse::parser::{ForceCollect, Parser};
|
||||
use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal};
|
||||
use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error};
|
||||
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{Pos, Span, Symbol};
|
||||
|
@ -209,9 +209,10 @@ pub(crate) fn expand_include_str(
|
|||
let interned_src = Symbol::intern(src);
|
||||
MacEager::expr(cx.expr_str(cx.with_def_site_ctxt(bsp), interned_src))
|
||||
}
|
||||
Err(_) => {
|
||||
let guar = cx.dcx().span_err(sp, format!("`{path}` wasn't a utf-8 file"));
|
||||
DummyResult::any(sp, guar)
|
||||
Err(utf8err) => {
|
||||
let mut err = cx.dcx().struct_span_err(sp, format!("`{path}` wasn't a utf-8 file"));
|
||||
utf8_error(cx.source_map(), path.as_str(), None, &mut err, utf8err, &bytes[..]);
|
||||
DummyResult::any(sp, err.emit())
|
||||
}
|
||||
},
|
||||
Err(dummy) => dummy,
|
||||
|
@ -273,7 +274,7 @@ fn load_binary_file(
|
|||
.and_then(|path| path.into_os_string().into_string().ok());
|
||||
|
||||
if let Some(new_path) = new_path {
|
||||
err.span_suggestion(
|
||||
err.span_suggestion_verbose(
|
||||
path_span,
|
||||
"there is a file with the same name in a different directory",
|
||||
format!("\"{}\"", new_path.replace('\\', "/").escape_debug()),
|
||||
|
|
|
@ -1528,9 +1528,9 @@ fn report_ice(
|
|||
// If backtraces are enabled, also print the query stack
|
||||
let backtrace = env::var_os("RUST_BACKTRACE").is_some_and(|x| &x != "0");
|
||||
|
||||
let num_frames = if backtrace { None } else { Some(2) };
|
||||
let limit_frames = if backtrace { None } else { Some(2) };
|
||||
|
||||
interface::try_print_query_stack(dcx, num_frames, file);
|
||||
interface::try_print_query_stack(dcx, limit_frames, file);
|
||||
|
||||
// We don't trust this callback not to panic itself, so run it at the end after we're sure we've
|
||||
// printed all the relevant info.
|
||||
|
|
|
@ -2349,6 +2349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.report_missing_fields(
|
||||
adt_ty,
|
||||
path_span,
|
||||
expr.span,
|
||||
remaining_fields,
|
||||
variant,
|
||||
hir_fields,
|
||||
|
@ -2386,6 +2387,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&self,
|
||||
adt_ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
full_span: Span,
|
||||
remaining_fields: UnordMap<Ident, (FieldIdx, &ty::FieldDef)>,
|
||||
variant: &'tcx ty::VariantDef,
|
||||
hir_fields: &'tcx [hir::ExprField<'tcx>],
|
||||
|
@ -2425,6 +2427,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
);
|
||||
err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}"));
|
||||
|
||||
if remaining_fields.items().all(|(_, (_, field))| field.value.is_some())
|
||||
&& self.tcx.sess.is_nightly_build()
|
||||
{
|
||||
let msg = format!(
|
||||
"all remaining fields have default values, {you_can} use those values with `..`",
|
||||
you_can = if self.tcx.features().default_field_values() {
|
||||
"you can"
|
||||
} else {
|
||||
"if you added `#![feature(default_field_values)]` to your crate you could"
|
||||
},
|
||||
);
|
||||
if let Some(hir_field) = hir_fields.last() {
|
||||
err.span_suggestion_verbose(
|
||||
hir_field.span.shrink_to_hi(),
|
||||
msg,
|
||||
", ..".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if hir_fields.is_empty() {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi().with_hi(full_span.hi()),
|
||||
msg,
|
||||
" { .. }".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(hir_field) = hir_fields.last() {
|
||||
self.suggest_fru_from_range_and_emit(hir_field, variant, args, err);
|
||||
} else {
|
||||
|
|
|
@ -533,7 +533,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
|
|||
|
||||
pub fn try_print_query_stack(
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
num_frames: Option<usize>,
|
||||
limit_frames: Option<usize>,
|
||||
file: Option<std::fs::File>,
|
||||
) {
|
||||
eprintln!("query stack during panic:");
|
||||
|
@ -541,13 +541,13 @@ pub fn try_print_query_stack(
|
|||
// Be careful relying on global state here: this code is called from
|
||||
// a panic hook, which means that the global `DiagCtxt` may be in a weird
|
||||
// state if it was responsible for triggering the panic.
|
||||
let i = ty::tls::with_context_opt(|icx| {
|
||||
let all_frames = ty::tls::with_context_opt(|icx| {
|
||||
if let Some(icx) = icx {
|
||||
ty::print::with_no_queries!(print_query_stack(
|
||||
QueryCtxt::new(icx.tcx),
|
||||
icx.query,
|
||||
dcx,
|
||||
num_frames,
|
||||
limit_frames,
|
||||
file,
|
||||
))
|
||||
} else {
|
||||
|
@ -555,9 +555,14 @@ pub fn try_print_query_stack(
|
|||
}
|
||||
});
|
||||
|
||||
if num_frames == None || num_frames >= Some(i) {
|
||||
eprintln!("end of query stack");
|
||||
if let Some(limit_frames) = limit_frames
|
||||
&& all_frames > limit_frames
|
||||
{
|
||||
eprintln!(
|
||||
"... and {} other queries... use `env RUST_BACKTRACE=1` to see the full query stack",
|
||||
all_frames - limit_frames
|
||||
);
|
||||
} else {
|
||||
eprintln!("we're just showing a limited slice of the query stack");
|
||||
eprintln!("end of query stack");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -209,7 +209,9 @@ lint_dangling_pointers_from_temporaries = a dangling pointer will be produced be
|
|||
.label_ptr = this pointer will immediately be invalid
|
||||
.label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||
.note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||
.help = for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||
.help_bind = you must make sure that the variable you bind the `{$ty}` to lives at least as long as the pointer returned by the call to `{$callee}`
|
||||
.help_returned = in particular, if this pointer is returned from the current function, binding the `{$ty}` inside the function will not suffice
|
||||
.help_visit = for more information, see <https://doc.rust-lang.org/reference/destructors.html>
|
||||
|
||||
lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
|
||||
.note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
|
||||
|
|
|
@ -1139,7 +1139,9 @@ pub(crate) struct IgnoredUnlessCrateSpecified<'a> {
|
|||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_dangling_pointers_from_temporaries)]
|
||||
#[note]
|
||||
#[help]
|
||||
#[help(lint_help_bind)]
|
||||
#[help(lint_help_returned)]
|
||||
#[help(lint_help_visit)]
|
||||
// FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts
|
||||
pub(crate) struct DanglingPointersFromTemporaries<'tcx> {
|
||||
pub callee: Symbol,
|
||||
|
|
|
@ -1986,6 +1986,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
let false_edge_start_block = candidate.subcandidates[0].false_edge_start_block;
|
||||
candidate.subcandidates.retain_mut(|candidate| {
|
||||
if candidate.extra_data.is_never {
|
||||
candidate.visit_leaves(|subcandidate| {
|
||||
|
@ -2000,8 +2001,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
});
|
||||
if candidate.subcandidates.is_empty() {
|
||||
// If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block`.
|
||||
candidate.pre_binding_block = Some(self.cfg.start_new_block());
|
||||
// If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block` and `otherwise_block`.
|
||||
let next_block = self.cfg.start_new_block();
|
||||
candidate.pre_binding_block = Some(next_block);
|
||||
candidate.otherwise_block = Some(next_block);
|
||||
// In addition, if `candidate` doesn't have `false_edge_start_block`, it should be assigned here.
|
||||
if candidate.false_edge_start_block.is_none() {
|
||||
candidate.false_edge_start_block = false_edge_start_block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,18 +11,21 @@
|
|||
#![feature(if_let_guard)]
|
||||
#![feature(iter_intersperse)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(string_from_utf8_lossy_owned)]
|
||||
#![warn(unreachable_pub)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::Utf8Error;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{AttrItem, Attribute, MetaItemInner, token};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{Diag, FatalError, PResult};
|
||||
use rustc_errors::{Diag, EmissionGuarantee, FatalError, PResult, pluralize};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{FileName, SourceFile, Span};
|
||||
pub use unicode_normalization::UNICODE_VERSION as UNICODE_NORMALIZATION_VERSION;
|
||||
|
||||
|
@ -73,9 +76,22 @@ pub fn new_parser_from_file<'a>(
|
|||
path: &Path,
|
||||
sp: Option<Span>,
|
||||
) -> Result<Parser<'a>, Vec<Diag<'a>>> {
|
||||
let source_file = psess.source_map().load_file(path).unwrap_or_else(|e| {
|
||||
let msg = format!("couldn't read {}: {}", path.display(), e);
|
||||
let sm = psess.source_map();
|
||||
let source_file = sm.load_file(path).unwrap_or_else(|e| {
|
||||
let msg = format!("couldn't read `{}`: {}", path.display(), e);
|
||||
let mut err = psess.dcx().struct_fatal(msg);
|
||||
if let Ok(contents) = std::fs::read(path)
|
||||
&& let Err(utf8err) = String::from_utf8(contents.clone())
|
||||
{
|
||||
utf8_error(
|
||||
sm,
|
||||
&path.display().to_string(),
|
||||
sp,
|
||||
&mut err,
|
||||
utf8err.utf8_error(),
|
||||
&contents,
|
||||
);
|
||||
}
|
||||
if let Some(sp) = sp {
|
||||
err.span(sp);
|
||||
}
|
||||
|
@ -84,6 +100,49 @@ pub fn new_parser_from_file<'a>(
|
|||
new_parser_from_source_file(psess, source_file)
|
||||
}
|
||||
|
||||
pub fn utf8_error<E: EmissionGuarantee>(
|
||||
sm: &SourceMap,
|
||||
path: &str,
|
||||
sp: Option<Span>,
|
||||
err: &mut Diag<'_, E>,
|
||||
utf8err: Utf8Error,
|
||||
contents: &[u8],
|
||||
) {
|
||||
// The file exists, but it wasn't valid UTF-8.
|
||||
let start = utf8err.valid_up_to();
|
||||
let note = format!("invalid utf-8 at byte `{start}`");
|
||||
let msg = if let Some(len) = utf8err.error_len() {
|
||||
format!(
|
||||
"byte{s} `{bytes}` {are} not valid utf-8",
|
||||
bytes = if len == 1 {
|
||||
format!("{:?}", contents[start])
|
||||
} else {
|
||||
format!("{:?}", &contents[start..start + len])
|
||||
},
|
||||
s = pluralize!(len),
|
||||
are = if len == 1 { "is" } else { "are" },
|
||||
)
|
||||
} else {
|
||||
note.clone()
|
||||
};
|
||||
let contents = String::from_utf8_lossy(contents).to_string();
|
||||
let source = sm.new_source_file(PathBuf::from(path).into(), contents);
|
||||
let span = Span::with_root_ctxt(
|
||||
source.normalized_byte_pos(start as u32),
|
||||
source.normalized_byte_pos(start as u32),
|
||||
);
|
||||
if span.is_dummy() {
|
||||
err.note(note);
|
||||
} else {
|
||||
if sp.is_some() {
|
||||
err.span_note(span, msg);
|
||||
} else {
|
||||
err.span(span);
|
||||
err.span_label(span, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a session and a `source_file`, return a parser. Returns any buffered errors from lexing
|
||||
/// the initial token stream.
|
||||
fn new_parser_from_source_file(
|
||||
|
|
|
@ -567,7 +567,7 @@ pub fn print_query_stack<Qcx: QueryContext>(
|
|||
qcx: Qcx,
|
||||
mut current_query: Option<QueryJobId>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
num_frames: Option<usize>,
|
||||
limit_frames: Option<usize>,
|
||||
mut file: Option<std::fs::File>,
|
||||
) -> usize {
|
||||
// Be careful relying on global state here: this code is called from
|
||||
|
@ -584,7 +584,7 @@ pub fn print_query_stack<Qcx: QueryContext>(
|
|||
let Some(query_info) = query_map.get(&query) else {
|
||||
break;
|
||||
};
|
||||
if Some(count_printed) < num_frames || num_frames.is_none() {
|
||||
if Some(count_printed) < limit_frames || limit_frames.is_none() {
|
||||
// Only print to stderr as many stack frames as `num_frames` when present.
|
||||
// FIXME: needs translation
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
|
@ -615,5 +615,5 @@ pub fn print_query_stack<Qcx: QueryContext>(
|
|||
if let Some(ref mut file) = file {
|
||||
let _ = writeln!(file, "end of query stack");
|
||||
}
|
||||
count_printed
|
||||
count_total
|
||||
}
|
||||
|
|
|
@ -645,10 +645,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
let self_spans = items
|
||||
.iter()
|
||||
.filter_map(|(use_tree, _)| {
|
||||
if let ast::UseTreeKind::Simple(..) = use_tree.kind {
|
||||
if use_tree.ident().name == kw::SelfLower {
|
||||
return Some(use_tree.span);
|
||||
}
|
||||
if let ast::UseTreeKind::Simple(..) = use_tree.kind
|
||||
&& use_tree.ident().name == kw::SelfLower
|
||||
{
|
||||
return Some(use_tree.span);
|
||||
}
|
||||
|
||||
None
|
||||
|
@ -947,19 +947,19 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
let imported_binding = self.r.import(binding, import);
|
||||
if parent == self.r.graph_root {
|
||||
let ident = ident.normalize_to_macros_2_0();
|
||||
if let Some(entry) = self.r.extern_prelude.get(&ident) {
|
||||
if expansion != LocalExpnId::ROOT && orig_name.is_some() && !entry.is_import() {
|
||||
self.r.dcx().emit_err(
|
||||
errors::MacroExpandedExternCrateCannotShadowExternArguments {
|
||||
span: item.span,
|
||||
},
|
||||
);
|
||||
// `return` is intended to discard this binding because it's an
|
||||
// unregistered ambiguity error which would result in a panic
|
||||
// caused by inconsistency `path_res`
|
||||
// more details: https://github.com/rust-lang/rust/pull/111761
|
||||
return;
|
||||
}
|
||||
if let Some(entry) = self.r.extern_prelude.get(&ident)
|
||||
&& expansion != LocalExpnId::ROOT
|
||||
&& orig_name.is_some()
|
||||
&& !entry.is_import()
|
||||
{
|
||||
self.r.dcx().emit_err(
|
||||
errors::MacroExpandedExternCrateCannotShadowExternArguments { span: item.span },
|
||||
);
|
||||
// `return` is intended to discard this binding because it's an
|
||||
// unregistered ambiguity error which would result in a panic
|
||||
// caused by inconsistency `path_res`
|
||||
// more details: https://github.com/rust-lang/rust/pull/111761
|
||||
return;
|
||||
}
|
||||
let entry = self
|
||||
.r
|
||||
|
@ -1040,10 +1040,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
span: item.span,
|
||||
});
|
||||
}
|
||||
if let ItemKind::ExternCrate(Some(orig_name)) = item.kind {
|
||||
if orig_name == kw::SelfLower {
|
||||
self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span: attr.span });
|
||||
}
|
||||
if let ItemKind::ExternCrate(Some(orig_name)) = item.kind
|
||||
&& orig_name == kw::SelfLower
|
||||
{
|
||||
self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span: attr.span });
|
||||
}
|
||||
let ill_formed = |span| {
|
||||
self.r.dcx().emit_err(errors::BadMacroImport { span });
|
||||
|
@ -1179,14 +1179,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
return Some((MacroKind::Bang, item.ident, item.span));
|
||||
} else if ast::attr::contains_name(&item.attrs, sym::proc_macro_attribute) {
|
||||
return Some((MacroKind::Attr, item.ident, item.span));
|
||||
} else if let Some(attr) = ast::attr::find_by_name(&item.attrs, sym::proc_macro_derive) {
|
||||
if let Some(meta_item_inner) =
|
||||
} else if let Some(attr) = ast::attr::find_by_name(&item.attrs, sym::proc_macro_derive)
|
||||
&& let Some(meta_item_inner) =
|
||||
attr.meta_item_list().and_then(|list| list.get(0).cloned())
|
||||
{
|
||||
if let Some(ident) = meta_item_inner.ident() {
|
||||
return Some((MacroKind::Derive, ident, ident.span));
|
||||
}
|
||||
}
|
||||
&& let Some(ident) = meta_item_inner.ident()
|
||||
{
|
||||
return Some((MacroKind::Derive, ident, ident.span));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
|
@ -225,10 +225,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
let (name, 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 {
|
||||
return;
|
||||
}
|
||||
if self.name_already_seen.get(&name) == Some(&span) {
|
||||
return;
|
||||
}
|
||||
|
||||
let old_kind = match (ns, old_binding.module()) {
|
||||
|
@ -380,20 +378,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
suggestion = Some(format!("self as {suggested_name}"))
|
||||
}
|
||||
ImportKind::Single { source, .. } => {
|
||||
if let Some(pos) =
|
||||
source.span.hi().0.checked_sub(binding_span.lo().0).map(|pos| pos as usize)
|
||||
if let Some(pos) = source.span.hi().0.checked_sub(binding_span.lo().0)
|
||||
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span)
|
||||
&& pos as usize <= snippet.len()
|
||||
{
|
||||
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span) {
|
||||
if pos <= snippet.len() {
|
||||
span = binding_span
|
||||
.with_lo(binding_span.lo() + BytePos(pos as u32))
|
||||
.with_hi(
|
||||
binding_span.hi()
|
||||
- BytePos(if snippet.ends_with(';') { 1 } else { 0 }),
|
||||
);
|
||||
suggestion = Some(format!(" as {suggested_name}"));
|
||||
}
|
||||
}
|
||||
span = binding_span.with_lo(binding_span.lo() + BytePos(pos)).with_hi(
|
||||
binding_span.hi() - BytePos(if snippet.ends_with(';') { 1 } else { 0 }),
|
||||
);
|
||||
suggestion = Some(format!(" as {suggested_name}"));
|
||||
}
|
||||
}
|
||||
ImportKind::ExternCrate { source, target, .. } => {
|
||||
|
@ -510,13 +502,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
// If the first element of our path was actually resolved to an
|
||||
// `ExternCrate` (also used for `crate::...`) then no need to issue a
|
||||
// warning, this looks all good!
|
||||
if let Some(binding) = second_binding {
|
||||
if let NameBindingKind::Import { import, .. } = binding.kind {
|
||||
// Careful: we still want to rewrite paths from renamed extern crates.
|
||||
if let ImportKind::ExternCrate { source: None, .. } = import.kind {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if let Some(binding) = second_binding
|
||||
&& let NameBindingKind::Import { import, .. } = binding.kind
|
||||
// Careful: we still want to rewrite paths from renamed extern crates.
|
||||
&& let ImportKind::ExternCrate { source: None, .. } = import.kind
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let diag = BuiltinLintDiag::AbsPathWithModule(root_span);
|
||||
|
@ -1047,20 +1038,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
if filter_fn(res) {
|
||||
for derive in parent_scope.derives {
|
||||
let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
|
||||
if let Ok((Some(ext), _)) = this.resolve_macro_path(
|
||||
let Ok((Some(ext), _)) = this.resolve_macro_path(
|
||||
derive,
|
||||
Some(MacroKind::Derive),
|
||||
parent_scope,
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
) {
|
||||
suggestions.extend(
|
||||
ext.helper_attrs
|
||||
.iter()
|
||||
.map(|name| TypoSuggestion::typo_from_name(*name, res)),
|
||||
);
|
||||
}
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
suggestions.extend(
|
||||
ext.helper_attrs
|
||||
.iter()
|
||||
.map(|name| TypoSuggestion::typo_from_name(*name, res)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1215,12 +1207,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
}
|
||||
|
||||
// #90113: Do not count an inaccessible reexported item as a candidate.
|
||||
if let NameBindingKind::Import { binding, .. } = name_binding.kind {
|
||||
if this.is_accessible_from(binding.vis, parent_scope.module)
|
||||
&& !this.is_accessible_from(name_binding.vis, parent_scope.module)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if let NameBindingKind::Import { binding, .. } = name_binding.kind
|
||||
&& this.is_accessible_from(binding.vis, parent_scope.module)
|
||||
&& !this.is_accessible_from(name_binding.vis, parent_scope.module)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let res = name_binding.res();
|
||||
|
@ -1253,14 +1244,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
segms.push(ast::PathSegment::from_ident(ident));
|
||||
let path = Path { span: name_binding.span, segments: segms, tokens: None };
|
||||
|
||||
if child_accessible {
|
||||
if child_accessible
|
||||
// Remove invisible match if exists
|
||||
if let Some(idx) = candidates
|
||||
&& let Some(idx) = candidates
|
||||
.iter()
|
||||
.position(|v: &ImportSuggestion| v.did == did && !v.accessible)
|
||||
{
|
||||
candidates.remove(idx);
|
||||
}
|
||||
{
|
||||
candidates.remove(idx);
|
||||
}
|
||||
|
||||
if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
|
||||
|
@ -1373,48 +1363,50 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
// otherwise cause duplicate suggestions.
|
||||
continue;
|
||||
}
|
||||
let crate_id = self.crate_loader(|c| c.maybe_process_path_extern(ident.name));
|
||||
if let Some(crate_id) = crate_id {
|
||||
let crate_def_id = crate_id.as_def_id();
|
||||
let crate_root = self.expect_module(crate_def_id);
|
||||
let Some(crate_id) = self.crate_loader(|c| c.maybe_process_path_extern(ident.name))
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Check if there's already an item in scope with the same name as the crate.
|
||||
// If so, we have to disambiguate the potential import suggestions by making
|
||||
// the paths *global* (i.e., by prefixing them with `::`).
|
||||
let needs_disambiguation =
|
||||
self.resolutions(parent_scope.module).borrow().iter().any(
|
||||
|(key, name_resolution)| {
|
||||
if key.ns == TypeNS
|
||||
&& key.ident == ident
|
||||
&& let Some(binding) = name_resolution.borrow().binding
|
||||
{
|
||||
match binding.res() {
|
||||
// No disambiguation needed if the identically named item we
|
||||
// found in scope actually refers to the crate in question.
|
||||
Res::Def(_, def_id) => def_id != crate_def_id,
|
||||
Res::PrimTy(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
let crate_def_id = crate_id.as_def_id();
|
||||
let crate_root = self.expect_module(crate_def_id);
|
||||
|
||||
// Check if there's already an item in scope with the same name as the crate.
|
||||
// If so, we have to disambiguate the potential import suggestions by making
|
||||
// the paths *global* (i.e., by prefixing them with `::`).
|
||||
let needs_disambiguation =
|
||||
self.resolutions(parent_scope.module).borrow().iter().any(
|
||||
|(key, name_resolution)| {
|
||||
if key.ns == TypeNS
|
||||
&& key.ident == ident
|
||||
&& let Some(binding) = name_resolution.borrow().binding
|
||||
{
|
||||
match binding.res() {
|
||||
// No disambiguation needed if the identically named item we
|
||||
// found in scope actually refers to the crate in question.
|
||||
Res::Def(_, def_id) => def_id != crate_def_id,
|
||||
Res::PrimTy(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
},
|
||||
);
|
||||
let mut crate_path = ThinVec::new();
|
||||
if needs_disambiguation {
|
||||
crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP));
|
||||
}
|
||||
crate_path.push(ast::PathSegment::from_ident(ident));
|
||||
|
||||
suggestions.extend(self.lookup_import_candidates_from_module(
|
||||
lookup_ident,
|
||||
namespace,
|
||||
parent_scope,
|
||||
crate_root,
|
||||
crate_path,
|
||||
&filter_fn,
|
||||
));
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
);
|
||||
let mut crate_path = ThinVec::new();
|
||||
if needs_disambiguation {
|
||||
crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP));
|
||||
}
|
||||
crate_path.push(ast::PathSegment::from_ident(ident));
|
||||
|
||||
suggestions.extend(self.lookup_import_candidates_from_module(
|
||||
lookup_ident,
|
||||
namespace,
|
||||
parent_scope,
|
||||
crate_root,
|
||||
crate_path,
|
||||
&filter_fn,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1511,7 +1503,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
});
|
||||
}
|
||||
for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
|
||||
if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
|
||||
let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
|
||||
ident,
|
||||
ScopeSet::All(ns),
|
||||
parent_scope,
|
||||
|
@ -1519,53 +1511,53 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
false,
|
||||
None,
|
||||
None,
|
||||
) {
|
||||
let desc = match binding.res() {
|
||||
Res::Def(DefKind::Macro(MacroKind::Bang), _) => {
|
||||
"a function-like macro".to_string()
|
||||
}
|
||||
Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
|
||||
format!("an attribute: `#[{ident}]`")
|
||||
}
|
||||
Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
|
||||
format!("a derive macro: `#[derive({ident})]`")
|
||||
}
|
||||
Res::ToolMod => {
|
||||
// Don't confuse the user with tool modules.
|
||||
continue;
|
||||
}
|
||||
Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => {
|
||||
"only a trait, without a derive macro".to_string()
|
||||
}
|
||||
res => format!(
|
||||
"{} {}, not {} {}",
|
||||
res.article(),
|
||||
res.descr(),
|
||||
macro_kind.article(),
|
||||
macro_kind.descr_expected(),
|
||||
),
|
||||
};
|
||||
if let crate::NameBindingKind::Import { import, .. } = binding.kind {
|
||||
if !import.span.is_dummy() {
|
||||
let note = errors::IdentImporterHereButItIsDesc {
|
||||
span: import.span,
|
||||
imported_ident: ident,
|
||||
imported_ident_desc: &desc,
|
||||
};
|
||||
err.subdiagnostic(note);
|
||||
// Silence the 'unused import' warning we might get,
|
||||
// since this diagnostic already covers that import.
|
||||
self.record_use(ident, binding, Used::Other);
|
||||
return;
|
||||
}
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let desc = match binding.res() {
|
||||
Res::Def(DefKind::Macro(MacroKind::Bang), _) => "a function-like macro".to_string(),
|
||||
Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
|
||||
format!("an attribute: `#[{ident}]`")
|
||||
}
|
||||
let note = errors::IdentInScopeButItIsDesc {
|
||||
Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
|
||||
format!("a derive macro: `#[derive({ident})]`")
|
||||
}
|
||||
Res::ToolMod => {
|
||||
// Don't confuse the user with tool modules.
|
||||
continue;
|
||||
}
|
||||
Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => {
|
||||
"only a trait, without a derive macro".to_string()
|
||||
}
|
||||
res => format!(
|
||||
"{} {}, not {} {}",
|
||||
res.article(),
|
||||
res.descr(),
|
||||
macro_kind.article(),
|
||||
macro_kind.descr_expected(),
|
||||
),
|
||||
};
|
||||
if let crate::NameBindingKind::Import { import, .. } = binding.kind
|
||||
&& !import.span.is_dummy()
|
||||
{
|
||||
let note = errors::IdentImporterHereButItIsDesc {
|
||||
span: import.span,
|
||||
imported_ident: ident,
|
||||
imported_ident_desc: &desc,
|
||||
};
|
||||
err.subdiagnostic(note);
|
||||
// Silence the 'unused import' warning we might get,
|
||||
// since this diagnostic already covers that import.
|
||||
self.record_use(ident, binding, Used::Other);
|
||||
return;
|
||||
}
|
||||
let note = errors::IdentInScopeButItIsDesc {
|
||||
imported_ident: ident,
|
||||
imported_ident_desc: &desc,
|
||||
};
|
||||
err.subdiagnostic(note);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1749,15 +1741,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
/// If the binding refers to a tuple struct constructor with fields,
|
||||
/// returns the span of its fields.
|
||||
fn ctor_fields_span(&self, binding: NameBinding<'_>) -> Option<Span> {
|
||||
if let NameBindingKind::Res(Res::Def(
|
||||
let NameBindingKind::Res(Res::Def(
|
||||
DefKind::Ctor(CtorOf::Struct, CtorKind::Fn),
|
||||
ctor_def_id,
|
||||
)) = binding.kind
|
||||
{
|
||||
let def_id = self.tcx.parent(ctor_def_id);
|
||||
return self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to); // None for `struct Foo()`
|
||||
}
|
||||
None
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let def_id = self.tcx.parent(ctor_def_id);
|
||||
self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to) // None for `struct Foo()`
|
||||
}
|
||||
|
||||
fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) {
|
||||
|
@ -1983,10 +1976,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
.collect::<Vec<_>>();
|
||||
candidates.sort();
|
||||
candidates.dedup();
|
||||
match find_best_match_for_name(&candidates, ident, None) {
|
||||
Some(sugg) if sugg == ident => None,
|
||||
sugg => sugg,
|
||||
}
|
||||
find_best_match_for_name(&candidates, ident, None).filter(|sugg| *sugg != ident)
|
||||
}
|
||||
|
||||
pub(crate) fn report_path_resolution_error(
|
||||
|
@ -2410,115 +2400,115 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
let binding_key = BindingKey::new(ident, MacroNS);
|
||||
let resolution = resolutions.get(&binding_key)?;
|
||||
let binding = resolution.borrow().binding()?;
|
||||
if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() {
|
||||
let module_name = crate_module.kind.name().unwrap();
|
||||
let import_snippet = match import.kind {
|
||||
ImportKind::Single { source, target, .. } if source != target => {
|
||||
format!("{source} as {target}")
|
||||
}
|
||||
_ => format!("{ident}"),
|
||||
};
|
||||
|
||||
let mut corrections: Vec<(Span, String)> = Vec::new();
|
||||
if !import.is_nested() {
|
||||
// Assume this is the easy case of `use issue_59764::foo::makro;` and just remove
|
||||
// intermediate segments.
|
||||
corrections.push((import.span, format!("{module_name}::{import_snippet}")));
|
||||
} else {
|
||||
// Find the binding span (and any trailing commas and spaces).
|
||||
// ie. `use a::b::{c, d, e};`
|
||||
// ^^^
|
||||
let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding(
|
||||
self.tcx.sess,
|
||||
import.span,
|
||||
import.use_span,
|
||||
);
|
||||
debug!(found_closing_brace, ?binding_span);
|
||||
|
||||
let mut removal_span = binding_span;
|
||||
if found_closing_brace {
|
||||
// If the binding span ended with a closing brace, as in the below example:
|
||||
// ie. `use a::b::{c, d};`
|
||||
// ^
|
||||
// Then expand the span of characters to remove to include the previous
|
||||
// binding's trailing comma.
|
||||
// ie. `use a::b::{c, d};`
|
||||
// ^^^
|
||||
if let Some(previous_span) =
|
||||
extend_span_to_previous_binding(self.tcx.sess, binding_span)
|
||||
{
|
||||
debug!(?previous_span);
|
||||
removal_span = removal_span.with_lo(previous_span.lo());
|
||||
}
|
||||
}
|
||||
debug!(?removal_span);
|
||||
|
||||
// Remove the `removal_span`.
|
||||
corrections.push((removal_span, "".to_string()));
|
||||
|
||||
// Find the span after the crate name and if it has nested imports immediately
|
||||
// after the crate name already.
|
||||
// ie. `use a::b::{c, d};`
|
||||
// ^^^^^^^^^
|
||||
// or `use a::{b, c, d}};`
|
||||
// ^^^^^^^^^^^
|
||||
let (has_nested, after_crate_name) = find_span_immediately_after_crate_name(
|
||||
self.tcx.sess,
|
||||
module_name,
|
||||
import.use_span,
|
||||
);
|
||||
debug!(has_nested, ?after_crate_name);
|
||||
|
||||
let source_map = self.tcx.sess.source_map();
|
||||
|
||||
// Make sure this is actually crate-relative.
|
||||
let is_definitely_crate = import
|
||||
.module_path
|
||||
.first()
|
||||
.is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super);
|
||||
|
||||
// Add the import to the start, with a `{` if required.
|
||||
let start_point = source_map.start_point(after_crate_name);
|
||||
if is_definitely_crate
|
||||
&& let Ok(start_snippet) = source_map.span_to_snippet(start_point)
|
||||
{
|
||||
corrections.push((
|
||||
start_point,
|
||||
if has_nested {
|
||||
// In this case, `start_snippet` must equal '{'.
|
||||
format!("{start_snippet}{import_snippet}, ")
|
||||
} else {
|
||||
// In this case, add a `{`, then the moved import, then whatever
|
||||
// was there before.
|
||||
format!("{{{import_snippet}, {start_snippet}")
|
||||
},
|
||||
));
|
||||
|
||||
// Add a `};` to the end if nested, matching the `{` added at the start.
|
||||
if !has_nested {
|
||||
corrections
|
||||
.push((source_map.end_point(after_crate_name), "};".to_string()));
|
||||
}
|
||||
} else {
|
||||
// If the root import is module-relative, add the import separately
|
||||
corrections.push((
|
||||
import.use_span.shrink_to_lo(),
|
||||
format!("use {module_name}::{import_snippet};\n"),
|
||||
));
|
||||
}
|
||||
let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else {
|
||||
return None;
|
||||
};
|
||||
let module_name = crate_module.kind.name().unwrap();
|
||||
let import_snippet = match import.kind {
|
||||
ImportKind::Single { source, target, .. } if source != target => {
|
||||
format!("{source} as {target}")
|
||||
}
|
||||
_ => format!("{ident}"),
|
||||
};
|
||||
|
||||
let suggestion = Some((
|
||||
corrections,
|
||||
String::from("a macro with this name exists at the root of the crate"),
|
||||
Applicability::MaybeIncorrect,
|
||||
));
|
||||
Some((suggestion, Some("this could be because a macro annotated with `#[macro_export]` will be exported \
|
||||
at the root of the crate instead of the module where it is defined"
|
||||
.to_string())))
|
||||
let mut corrections: Vec<(Span, String)> = Vec::new();
|
||||
if !import.is_nested() {
|
||||
// Assume this is the easy case of `use issue_59764::foo::makro;` and just remove
|
||||
// intermediate segments.
|
||||
corrections.push((import.span, format!("{module_name}::{import_snippet}")));
|
||||
} else {
|
||||
None
|
||||
// Find the binding span (and any trailing commas and spaces).
|
||||
// ie. `use a::b::{c, d, e};`
|
||||
// ^^^
|
||||
let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding(
|
||||
self.tcx.sess,
|
||||
import.span,
|
||||
import.use_span,
|
||||
);
|
||||
debug!(found_closing_brace, ?binding_span);
|
||||
|
||||
let mut removal_span = binding_span;
|
||||
|
||||
// If the binding span ended with a closing brace, as in the below example:
|
||||
// ie. `use a::b::{c, d};`
|
||||
// ^
|
||||
// Then expand the span of characters to remove to include the previous
|
||||
// binding's trailing comma.
|
||||
// ie. `use a::b::{c, d};`
|
||||
// ^^^
|
||||
if found_closing_brace
|
||||
&& let Some(previous_span) =
|
||||
extend_span_to_previous_binding(self.tcx.sess, binding_span)
|
||||
{
|
||||
debug!(?previous_span);
|
||||
removal_span = removal_span.with_lo(previous_span.lo());
|
||||
}
|
||||
debug!(?removal_span);
|
||||
|
||||
// Remove the `removal_span`.
|
||||
corrections.push((removal_span, "".to_string()));
|
||||
|
||||
// Find the span after the crate name and if it has nested imports immediately
|
||||
// after the crate name already.
|
||||
// ie. `use a::b::{c, d};`
|
||||
// ^^^^^^^^^
|
||||
// or `use a::{b, c, d}};`
|
||||
// ^^^^^^^^^^^
|
||||
let (has_nested, after_crate_name) =
|
||||
find_span_immediately_after_crate_name(self.tcx.sess, module_name, import.use_span);
|
||||
debug!(has_nested, ?after_crate_name);
|
||||
|
||||
let source_map = self.tcx.sess.source_map();
|
||||
|
||||
// Make sure this is actually crate-relative.
|
||||
let is_definitely_crate = import
|
||||
.module_path
|
||||
.first()
|
||||
.is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super);
|
||||
|
||||
// Add the import to the start, with a `{` if required.
|
||||
let start_point = source_map.start_point(after_crate_name);
|
||||
if is_definitely_crate
|
||||
&& let Ok(start_snippet) = source_map.span_to_snippet(start_point)
|
||||
{
|
||||
corrections.push((
|
||||
start_point,
|
||||
if has_nested {
|
||||
// In this case, `start_snippet` must equal '{'.
|
||||
format!("{start_snippet}{import_snippet}, ")
|
||||
} else {
|
||||
// In this case, add a `{`, then the moved import, then whatever
|
||||
// was there before.
|
||||
format!("{{{import_snippet}, {start_snippet}")
|
||||
},
|
||||
));
|
||||
|
||||
// Add a `};` to the end if nested, matching the `{` added at the start.
|
||||
if !has_nested {
|
||||
corrections.push((source_map.end_point(after_crate_name), "};".to_string()));
|
||||
}
|
||||
} else {
|
||||
// If the root import is module-relative, add the import separately
|
||||
corrections.push((
|
||||
import.use_span.shrink_to_lo(),
|
||||
format!("use {module_name}::{import_snippet};\n"),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let suggestion = Some((
|
||||
corrections,
|
||||
String::from("a macro with this name exists at the root of the crate"),
|
||||
Applicability::MaybeIncorrect,
|
||||
));
|
||||
Some((
|
||||
suggestion,
|
||||
Some(
|
||||
"this could be because a macro annotated with `#[macro_export]` will be exported \
|
||||
at the root of the crate instead of the module where it is defined"
|
||||
.to_string(),
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
/// Finds a cfg-ed out item inside `module` with the matching name.
|
||||
|
@ -3042,7 +3032,6 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
|
|||
self.first_legal_span = Some(inject);
|
||||
}
|
||||
self.first_use_span = search_for_any_use_in_items(&c.items);
|
||||
return;
|
||||
} else {
|
||||
visit::walk_crate(self, c);
|
||||
}
|
||||
|
@ -3056,7 +3045,6 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
|
|||
self.first_legal_span = Some(inject);
|
||||
}
|
||||
self.first_use_span = search_for_any_use_in_items(items);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
visit::walk_item(self, item);
|
||||
|
@ -3066,16 +3054,16 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
|
|||
|
||||
fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> {
|
||||
for item in items {
|
||||
if let ItemKind::Use(..) = item.kind {
|
||||
if is_span_suitable_for_use_injection(item.span) {
|
||||
let mut lo = item.span.lo();
|
||||
for attr in &item.attrs {
|
||||
if attr.span.eq_ctxt(item.span) {
|
||||
lo = std::cmp::min(lo, attr.span.lo());
|
||||
}
|
||||
if let ItemKind::Use(..) = item.kind
|
||||
&& is_span_suitable_for_use_injection(item.span)
|
||||
{
|
||||
let mut lo = item.span.lo();
|
||||
for attr in &item.attrs {
|
||||
if attr.span.eq_ctxt(item.span) {
|
||||
lo = std::cmp::min(lo, attr.span.lo());
|
||||
}
|
||||
return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent()));
|
||||
}
|
||||
return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent()));
|
||||
}
|
||||
}
|
||||
None
|
||||
|
|
|
@ -118,37 +118,38 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
|
|||
let resolutions = self.r.resolutions(module);
|
||||
|
||||
for (_, name_resolution) in resolutions.borrow().iter() {
|
||||
if let Some(mut binding) = name_resolution.borrow().binding() {
|
||||
// Set the given effective visibility level to `Level::Direct` and
|
||||
// sets the rest of the `use` chain to `Level::Reexported` until
|
||||
// we hit the actual exported item.
|
||||
//
|
||||
// If the binding is ambiguous, put the root ambiguity binding and all reexports
|
||||
// leading to it into the table. They are used by the `ambiguous_glob_reexports`
|
||||
// lint. For all bindings added to the table this way `is_ambiguity` returns true.
|
||||
let is_ambiguity =
|
||||
|binding: NameBinding<'ra>, warn: bool| binding.ambiguity.is_some() && !warn;
|
||||
let mut parent_id = ParentId::Def(module_id);
|
||||
let mut warn_ambiguity = binding.warn_ambiguity;
|
||||
while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind {
|
||||
self.update_import(binding, parent_id);
|
||||
let Some(mut binding) = name_resolution.borrow().binding() else {
|
||||
continue;
|
||||
};
|
||||
// Set the given effective visibility level to `Level::Direct` and
|
||||
// sets the rest of the `use` chain to `Level::Reexported` until
|
||||
// we hit the actual exported item.
|
||||
//
|
||||
// If the binding is ambiguous, put the root ambiguity binding and all reexports
|
||||
// leading to it into the table. They are used by the `ambiguous_glob_reexports`
|
||||
// lint. For all bindings added to the table this way `is_ambiguity` returns true.
|
||||
let is_ambiguity =
|
||||
|binding: NameBinding<'ra>, warn: bool| binding.ambiguity.is_some() && !warn;
|
||||
let mut parent_id = ParentId::Def(module_id);
|
||||
let mut warn_ambiguity = binding.warn_ambiguity;
|
||||
while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind {
|
||||
self.update_import(binding, parent_id);
|
||||
|
||||
if is_ambiguity(binding, warn_ambiguity) {
|
||||
// Stop at the root ambiguity, further bindings in the chain should not
|
||||
// be reexported because the root ambiguity blocks any access to them.
|
||||
// (Those further bindings are most likely not ambiguities themselves.)
|
||||
break;
|
||||
}
|
||||
if is_ambiguity(binding, warn_ambiguity) {
|
||||
// Stop at the root ambiguity, further bindings in the chain should not
|
||||
// be reexported because the root ambiguity blocks any access to them.
|
||||
// (Those further bindings are most likely not ambiguities themselves.)
|
||||
break;
|
||||
}
|
||||
|
||||
parent_id = ParentId::Import(binding);
|
||||
binding = nested_binding;
|
||||
warn_ambiguity |= nested_binding.warn_ambiguity;
|
||||
}
|
||||
if !is_ambiguity(binding, warn_ambiguity)
|
||||
&& let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local())
|
||||
{
|
||||
self.update_def(def_id, binding.vis.expect_local(), parent_id);
|
||||
}
|
||||
parent_id = ParentId::Import(binding);
|
||||
binding = nested_binding;
|
||||
warn_ambiguity |= nested_binding.warn_ambiguity;
|
||||
}
|
||||
if !is_ambiguity(binding, warn_ambiguity)
|
||||
&& let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local())
|
||||
{
|
||||
self.update_def(def_id, binding.vis.expect_local(), parent_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -246,23 +246,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
// ---- end
|
||||
// ```
|
||||
// So we have to fall back to the module's parent during lexical resolution in this case.
|
||||
if derive_fallback_lint_id.is_some() {
|
||||
if let Some(parent) = module.parent {
|
||||
// Inner module is inside the macro, parent module is outside of the macro.
|
||||
if module.expansion != parent.expansion
|
||||
&& module.expansion.is_descendant_of(parent.expansion)
|
||||
{
|
||||
// The macro is a proc macro derive
|
||||
if let Some(def_id) = module.expansion.expn_data().macro_def_id {
|
||||
let ext = &self.get_macro_by_def_id(def_id).ext;
|
||||
if ext.builtin_name.is_none()
|
||||
&& ext.macro_kind() == MacroKind::Derive
|
||||
&& parent.expansion.outer_expn_is_descendant_of(*ctxt)
|
||||
{
|
||||
return Some((parent, derive_fallback_lint_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
if derive_fallback_lint_id.is_some()
|
||||
&& let Some(parent) = module.parent
|
||||
// Inner module is inside the macro
|
||||
&& module.expansion != parent.expansion
|
||||
// Parent module is outside of the macro
|
||||
&& module.expansion.is_descendant_of(parent.expansion)
|
||||
// The macro is a proc macro derive
|
||||
&& let Some(def_id) = module.expansion.expn_data().macro_def_id
|
||||
{
|
||||
let ext = &self.get_macro_by_def_id(def_id).ext;
|
||||
if ext.builtin_name.is_none()
|
||||
&& ext.macro_kind() == MacroKind::Derive
|
||||
&& parent.expansion.outer_expn_is_descendant_of(*ctxt)
|
||||
{
|
||||
return Some((parent, derive_fallback_lint_id));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -593,8 +591,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
},
|
||||
Scope::StdLibPrelude => {
|
||||
let mut result = Err(Determinacy::Determined);
|
||||
if let Some(prelude) = this.prelude {
|
||||
if let Ok(binding) = this.resolve_ident_in_module_unadjusted(
|
||||
if let Some(prelude) = this.prelude
|
||||
&& let Ok(binding) = this.resolve_ident_in_module_unadjusted(
|
||||
ModuleOrUniformRoot::Module(prelude),
|
||||
ident,
|
||||
ns,
|
||||
|
@ -603,14 +601,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
None,
|
||||
ignore_binding,
|
||||
ignore_import,
|
||||
) {
|
||||
if matches!(use_prelude, UsePrelude::Yes)
|
||||
|| this.is_builtin_macro(binding.res())
|
||||
{
|
||||
result = Ok((binding, Flags::MISC_FROM_PRELUDE));
|
||||
}
|
||||
}
|
||||
)
|
||||
&& (matches!(use_prelude, UsePrelude::Yes)
|
||||
|| this.is_builtin_macro(binding.res()))
|
||||
{
|
||||
result = Ok((binding, Flags::MISC_FROM_PRELUDE));
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
Scope::BuiltinTypes => match this.builtin_types_bindings.get(&ident.name) {
|
||||
|
@ -939,10 +936,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
};
|
||||
|
||||
// Items and single imports are not shadowable, if we have one, then it's determined.
|
||||
if let Some(binding) = binding {
|
||||
if !binding.is_glob_import() {
|
||||
return check_usable(self, binding);
|
||||
}
|
||||
if let Some(binding) = binding
|
||||
&& !binding.is_glob_import()
|
||||
{
|
||||
return check_usable(self, binding);
|
||||
}
|
||||
|
||||
// --- From now on we either have a glob resolution or no resolution. ---
|
||||
|
@ -1437,13 +1434,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
for (segment_idx, &Segment { ident, id, .. }) in path.iter().enumerate() {
|
||||
debug!("resolve_path ident {} {:?} {:?}", segment_idx, ident, id);
|
||||
let record_segment_res = |this: &mut Self, res| {
|
||||
if finalize.is_some() {
|
||||
if let Some(id) = id {
|
||||
if !this.partial_res_map.contains_key(&id) {
|
||||
assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id");
|
||||
this.record_partial_res(id, PartialRes::new(res));
|
||||
}
|
||||
}
|
||||
if finalize.is_some()
|
||||
&& let Some(id) = id
|
||||
&& !this.partial_res_map.contains_key(&id)
|
||||
{
|
||||
assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id");
|
||||
this.record_partial_res(id, PartialRes::new(res));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1463,13 +1459,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
_ => None,
|
||||
},
|
||||
};
|
||||
if let Some(self_module) = self_module {
|
||||
if let Some(parent) = self_module.parent {
|
||||
module = Some(ModuleOrUniformRoot::Module(
|
||||
self.resolve_self(&mut ctxt, parent),
|
||||
));
|
||||
continue;
|
||||
}
|
||||
if let Some(self_module) = self_module
|
||||
&& let Some(parent) = self_module.parent
|
||||
{
|
||||
module =
|
||||
Some(ModuleOrUniformRoot::Module(self.resolve_self(&mut ctxt, parent)));
|
||||
continue;
|
||||
}
|
||||
return PathResult::failed(
|
||||
ident,
|
||||
|
@ -1644,13 +1639,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
}
|
||||
Err(Undetermined) => return PathResult::Indeterminate,
|
||||
Err(Determined) => {
|
||||
if let Some(ModuleOrUniformRoot::Module(module)) = module {
|
||||
if opt_ns.is_some() && !module.is_normal() {
|
||||
return PathResult::NonModule(PartialRes::with_unresolved_segments(
|
||||
module.res().unwrap(),
|
||||
path.len() - segment_idx,
|
||||
));
|
||||
}
|
||||
if let Some(ModuleOrUniformRoot::Module(module)) = module
|
||||
&& opt_ns.is_some()
|
||||
&& !module.is_normal()
|
||||
{
|
||||
return PathResult::NonModule(PartialRes::with_unresolved_segments(
|
||||
module.res().unwrap(),
|
||||
path.len() - segment_idx,
|
||||
));
|
||||
}
|
||||
|
||||
return PathResult::failed(
|
||||
|
|
|
@ -287,12 +287,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
binding.vis
|
||||
};
|
||||
|
||||
if let ImportKind::Glob { ref max_vis, .. } = import.kind {
|
||||
if vis == import_vis
|
||||
|| max_vis.get().is_none_or(|max_vis| vis.is_at_least(max_vis, self.tcx))
|
||||
{
|
||||
max_vis.set(Some(vis.expect_local()))
|
||||
}
|
||||
if let ImportKind::Glob { ref max_vis, .. } = import.kind
|
||||
&& (vis == import_vis
|
||||
|| max_vis.get().is_none_or(|max_vis| vis.is_at_least(max_vis, self.tcx)))
|
||||
{
|
||||
max_vis.set(Some(vis.expect_local()))
|
||||
}
|
||||
|
||||
self.arenas.alloc_name_binding(NameBindingData {
|
||||
|
@ -543,31 +542,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
// resolution for it so that later resolve stages won't complain.
|
||||
self.import_dummy_binding(*import, is_indeterminate);
|
||||
|
||||
if let Some(err) = unresolved_import_error {
|
||||
glob_error |= import.is_glob();
|
||||
let Some(err) = unresolved_import_error else { continue };
|
||||
|
||||
if let ImportKind::Single { source, ref source_bindings, .. } = import.kind {
|
||||
if source.name == kw::SelfLower {
|
||||
// Silence `unresolved import` error if E0429 is already emitted
|
||||
if let Err(Determined) = source_bindings.value_ns.get() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
glob_error |= import.is_glob();
|
||||
|
||||
if prev_root_id != NodeId::ZERO
|
||||
&& prev_root_id != import.root_id
|
||||
&& !errors.is_empty()
|
||||
{
|
||||
// In the case of a new import line, throw a diagnostic message
|
||||
// for the previous line.
|
||||
self.throw_unresolved_import_error(errors, glob_error);
|
||||
errors = vec![];
|
||||
}
|
||||
if seen_spans.insert(err.span) {
|
||||
errors.push((*import, err));
|
||||
prev_root_id = import.root_id;
|
||||
}
|
||||
if let ImportKind::Single { source, ref source_bindings, .. } = import.kind
|
||||
&& source.name == kw::SelfLower
|
||||
// Silence `unresolved import` error if E0429 is already emitted
|
||||
&& let Err(Determined) = source_bindings.value_ns.get()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if prev_root_id != NodeId::ZERO && prev_root_id != import.root_id && !errors.is_empty()
|
||||
{
|
||||
// In the case of a new import line, throw a diagnostic message
|
||||
// for the previous line.
|
||||
self.throw_unresolved_import_error(errors, glob_error);
|
||||
errors = vec![];
|
||||
}
|
||||
if seen_spans.insert(err.span) {
|
||||
errors.push((*import, err));
|
||||
prev_root_id = import.root_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -609,60 +605,60 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
for (key, resolution) in self.resolutions(*module).borrow().iter() {
|
||||
let resolution = resolution.borrow();
|
||||
|
||||
if let Some(binding) = resolution.binding {
|
||||
if let NameBindingKind::Import { import, .. } = binding.kind
|
||||
&& let Some((amb_binding, _)) = binding.ambiguity
|
||||
&& binding.res() != Res::Err
|
||||
&& exported_ambiguities.contains(&binding)
|
||||
let Some(binding) = resolution.binding else { continue };
|
||||
|
||||
if let NameBindingKind::Import { import, .. } = binding.kind
|
||||
&& let Some((amb_binding, _)) = binding.ambiguity
|
||||
&& binding.res() != Res::Err
|
||||
&& exported_ambiguities.contains(&binding)
|
||||
{
|
||||
self.lint_buffer.buffer_lint(
|
||||
AMBIGUOUS_GLOB_REEXPORTS,
|
||||
import.root_id,
|
||||
import.root_span,
|
||||
BuiltinLintDiag::AmbiguousGlobReexports {
|
||||
name: key.ident.to_string(),
|
||||
namespace: key.ns.descr().to_string(),
|
||||
first_reexport_span: import.root_span,
|
||||
duplicate_reexport_span: amb_binding.span,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(glob_binding) = resolution.shadowed_glob {
|
||||
let binding_id = match binding.kind {
|
||||
NameBindingKind::Res(res) => {
|
||||
Some(self.def_id_to_node_id[res.def_id().expect_local()])
|
||||
}
|
||||
NameBindingKind::Module(module) => {
|
||||
Some(self.def_id_to_node_id[module.def_id().expect_local()])
|
||||
}
|
||||
NameBindingKind::Import { import, .. } => import.id(),
|
||||
};
|
||||
|
||||
if binding.res() != Res::Err
|
||||
&& glob_binding.res() != Res::Err
|
||||
&& let NameBindingKind::Import { import: glob_import, .. } =
|
||||
glob_binding.kind
|
||||
&& let Some(binding_id) = binding_id
|
||||
&& let Some(glob_import_id) = glob_import.id()
|
||||
&& let glob_import_def_id = self.local_def_id(glob_import_id)
|
||||
&& self.effective_visibilities.is_exported(glob_import_def_id)
|
||||
&& glob_binding.vis.is_public()
|
||||
&& !binding.vis.is_public()
|
||||
{
|
||||
self.lint_buffer.buffer_lint(
|
||||
AMBIGUOUS_GLOB_REEXPORTS,
|
||||
import.root_id,
|
||||
import.root_span,
|
||||
BuiltinLintDiag::AmbiguousGlobReexports {
|
||||
name: key.ident.to_string(),
|
||||
namespace: key.ns.descr().to_string(),
|
||||
first_reexport_span: import.root_span,
|
||||
duplicate_reexport_span: amb_binding.span,
|
||||
HIDDEN_GLOB_REEXPORTS,
|
||||
binding_id,
|
||||
binding.span,
|
||||
BuiltinLintDiag::HiddenGlobReexports {
|
||||
name: key.ident.name.to_string(),
|
||||
namespace: key.ns.descr().to_owned(),
|
||||
glob_reexport_span: glob_binding.span,
|
||||
private_item_span: binding.span,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(glob_binding) = resolution.shadowed_glob {
|
||||
let binding_id = match binding.kind {
|
||||
NameBindingKind::Res(res) => {
|
||||
Some(self.def_id_to_node_id[res.def_id().expect_local()])
|
||||
}
|
||||
NameBindingKind::Module(module) => {
|
||||
Some(self.def_id_to_node_id[module.def_id().expect_local()])
|
||||
}
|
||||
NameBindingKind::Import { import, .. } => import.id(),
|
||||
};
|
||||
|
||||
if binding.res() != Res::Err
|
||||
&& glob_binding.res() != Res::Err
|
||||
&& let NameBindingKind::Import { import: glob_import, .. } =
|
||||
glob_binding.kind
|
||||
&& let Some(binding_id) = binding_id
|
||||
&& let Some(glob_import_id) = glob_import.id()
|
||||
&& let glob_import_def_id = self.local_def_id(glob_import_id)
|
||||
&& self.effective_visibilities.is_exported(glob_import_def_id)
|
||||
&& glob_binding.vis.is_public()
|
||||
&& !binding.vis.is_public()
|
||||
{
|
||||
self.lint_buffer.buffer_lint(
|
||||
HIDDEN_GLOB_REEXPORTS,
|
||||
binding_id,
|
||||
binding.span,
|
||||
BuiltinLintDiag::HiddenGlobReexports {
|
||||
name: key.ident.name.to_string(),
|
||||
namespace: key.ns.descr().to_owned(),
|
||||
glob_reexport_span: glob_binding.span,
|
||||
private_item_span: binding.span,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1006,21 +1002,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
self.lint_if_path_starts_with_module(Some(finalize), &full_path, None);
|
||||
}
|
||||
|
||||
if let ModuleOrUniformRoot::Module(module) = module {
|
||||
if module == import.parent_scope.module {
|
||||
// Importing a module into itself is not allowed.
|
||||
return Some(UnresolvedImportError {
|
||||
span: import.span,
|
||||
label: Some(String::from(
|
||||
"cannot glob-import a module into itself",
|
||||
)),
|
||||
note: None,
|
||||
suggestion: None,
|
||||
candidates: None,
|
||||
segment: None,
|
||||
module: None,
|
||||
});
|
||||
}
|
||||
if let ModuleOrUniformRoot::Module(module) = module
|
||||
&& module == import.parent_scope.module
|
||||
{
|
||||
// Importing a module into itself is not allowed.
|
||||
return Some(UnresolvedImportError {
|
||||
span: import.span,
|
||||
label: Some(String::from("cannot glob-import a module into itself")),
|
||||
note: None,
|
||||
suggestion: None,
|
||||
candidates: None,
|
||||
segment: None,
|
||||
module: None,
|
||||
});
|
||||
}
|
||||
if !is_prelude
|
||||
&& let Some(max_vis) = max_vis.get()
|
||||
|
@ -1081,18 +1075,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
// Consistency checks, analogous to `finalize_macro_resolutions`.
|
||||
let initial_res = source_bindings[ns].get().map(|initial_binding| {
|
||||
all_ns_err = false;
|
||||
if let Some(target_binding) = target_bindings[ns].get() {
|
||||
if target.name == kw::Underscore
|
||||
&& initial_binding.is_extern_crate()
|
||||
&& !initial_binding.is_import()
|
||||
{
|
||||
let used = if import.module_path.is_empty() {
|
||||
Used::Scope
|
||||
} else {
|
||||
Used::Other
|
||||
};
|
||||
this.record_use(ident, target_binding, used);
|
||||
}
|
||||
if let Some(target_binding) = target_bindings[ns].get()
|
||||
&& target.name == kw::Underscore
|
||||
&& initial_binding.is_extern_crate()
|
||||
&& !initial_binding.is_import()
|
||||
{
|
||||
let used = if import.module_path.is_empty() {
|
||||
Used::Scope
|
||||
} else {
|
||||
Used::Other
|
||||
};
|
||||
this.record_use(ident, target_binding, used);
|
||||
}
|
||||
initial_binding.res()
|
||||
});
|
||||
|
@ -1247,17 +1240,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
let mut any_successful_reexport = false;
|
||||
let mut crate_private_reexport = false;
|
||||
self.per_ns(|this, ns| {
|
||||
if let Ok(binding) = source_bindings[ns].get() {
|
||||
if !binding.vis.is_at_least(import.vis, this.tcx) {
|
||||
reexport_error = Some((ns, binding));
|
||||
if let ty::Visibility::Restricted(binding_def_id) = binding.vis {
|
||||
if binding_def_id.is_top_level_module() {
|
||||
crate_private_reexport = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
any_successful_reexport = true;
|
||||
let Ok(binding) = source_bindings[ns].get() else {
|
||||
return;
|
||||
};
|
||||
|
||||
if !binding.vis.is_at_least(import.vis, this.tcx) {
|
||||
reexport_error = Some((ns, binding));
|
||||
if let ty::Visibility::Restricted(binding_def_id) = binding.vis
|
||||
&& binding_def_id.is_top_level_module()
|
||||
{
|
||||
crate_private_reexport = true;
|
||||
}
|
||||
} else {
|
||||
any_successful_reexport = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1474,28 +1469,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
// 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 children = Vec::new();
|
||||
let Some(def_id) = module.opt_def_id() else { return };
|
||||
|
||||
module.for_each_child(self, |this, ident, _, binding| {
|
||||
let res = binding.res().expect_non_local();
|
||||
let error_ambiguity = binding.is_ambiguity_recursive() && !binding.warn_ambiguity;
|
||||
if res != def::Res::Err && !error_ambiguity {
|
||||
let mut reexport_chain = SmallVec::new();
|
||||
let mut next_binding = binding;
|
||||
while let NameBindingKind::Import { binding, import, .. } = next_binding.kind {
|
||||
reexport_chain.push(import.simplify(this));
|
||||
next_binding = binding;
|
||||
}
|
||||
let mut children = Vec::new();
|
||||
|
||||
children.push(ModChild { ident, res, vis: binding.vis, reexport_chain });
|
||||
module.for_each_child(self, |this, ident, _, binding| {
|
||||
let res = binding.res().expect_non_local();
|
||||
let error_ambiguity = binding.is_ambiguity_recursive() && !binding.warn_ambiguity;
|
||||
if res != def::Res::Err && !error_ambiguity {
|
||||
let mut reexport_chain = SmallVec::new();
|
||||
let mut next_binding = binding;
|
||||
while let NameBindingKind::Import { binding, import, .. } = next_binding.kind {
|
||||
reexport_chain.push(import.simplify(this));
|
||||
next_binding = binding;
|
||||
}
|
||||
});
|
||||
|
||||
if !children.is_empty() {
|
||||
// Should be fine because this code is only called for local modules.
|
||||
self.module_children.insert(def_id.expect_local(), children);
|
||||
children.push(ModChild { ident, res, vis: binding.vis, reexport_chain });
|
||||
}
|
||||
});
|
||||
|
||||
if !children.is_empty() {
|
||||
// Should be fine because this code is only called for local modules.
|
||||
self.module_children.insert(def_id.expect_local(), children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -468,16 +468,12 @@ impl<'a> PathSource<'a> {
|
|||
{
|
||||
"external crate"
|
||||
}
|
||||
ExprKind::Path(_, path) => {
|
||||
let mut msg = "function";
|
||||
if let Some(segment) = path.segments.iter().last() {
|
||||
if let Some(c) = segment.ident.to_string().chars().next() {
|
||||
if c.is_uppercase() {
|
||||
msg = "function, tuple struct or tuple variant";
|
||||
}
|
||||
}
|
||||
}
|
||||
msg
|
||||
ExprKind::Path(_, path)
|
||||
if let Some(segment) = path.segments.last()
|
||||
&& let Some(c) = segment.ident.to_string().chars().next()
|
||||
&& c.is_uppercase() =>
|
||||
{
|
||||
"function, tuple struct or tuple variant"
|
||||
}
|
||||
_ => "function",
|
||||
},
|
||||
|
@ -1182,32 +1178,27 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
|
|||
// namespace first, and if that fails we try again in the value namespace. If
|
||||
// resolution in the value namespace succeeds, we have an generic const argument on
|
||||
// our hands.
|
||||
if let TyKind::Path(None, ref path) = ty.kind {
|
||||
if let TyKind::Path(None, ref path) = ty.kind
|
||||
// We cannot disambiguate multi-segment paths right now as that requires type
|
||||
// checking.
|
||||
if path.is_potential_trivial_const_arg() {
|
||||
let mut check_ns = |ns| {
|
||||
self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns)
|
||||
.is_some()
|
||||
};
|
||||
if !check_ns(TypeNS) && check_ns(ValueNS) {
|
||||
self.resolve_anon_const_manual(
|
||||
true,
|
||||
AnonConstKind::ConstArg(IsRepeatExpr::No),
|
||||
|this| {
|
||||
this.smart_resolve_path(
|
||||
ty.id,
|
||||
&None,
|
||||
path,
|
||||
PathSource::Expr(None),
|
||||
);
|
||||
this.visit_path(path, ty.id);
|
||||
},
|
||||
);
|
||||
&& path.is_potential_trivial_const_arg()
|
||||
{
|
||||
let mut check_ns = |ns| {
|
||||
self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns)
|
||||
.is_some()
|
||||
};
|
||||
if !check_ns(TypeNS) && check_ns(ValueNS) {
|
||||
self.resolve_anon_const_manual(
|
||||
true,
|
||||
AnonConstKind::ConstArg(IsRepeatExpr::No),
|
||||
|this| {
|
||||
this.smart_resolve_path(ty.id, &None, path, PathSource::Expr(None));
|
||||
this.visit_path(path, ty.id);
|
||||
},
|
||||
);
|
||||
|
||||
self.diag_metadata.currently_processing_generic_args = prev;
|
||||
return;
|
||||
}
|
||||
self.diag_metadata.currently_processing_generic_args = prev;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1243,54 +1234,56 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
|
|||
}
|
||||
|
||||
fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) {
|
||||
if let Some(ref args) = path_segment.args {
|
||||
match &**args {
|
||||
GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, args),
|
||||
GenericArgs::Parenthesized(p_args) => {
|
||||
// Probe the lifetime ribs to know how to behave.
|
||||
for rib in self.lifetime_ribs.iter().rev() {
|
||||
match rib.kind {
|
||||
// We are inside a `PolyTraitRef`. The lifetimes are
|
||||
// to be introduced in that (maybe implicit) `for<>` binder.
|
||||
LifetimeRibKind::Generics {
|
||||
binder,
|
||||
kind: LifetimeBinderKind::PolyTrait,
|
||||
..
|
||||
} => {
|
||||
self.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousCreateParameter {
|
||||
let Some(ref args) = path_segment.args else {
|
||||
return;
|
||||
};
|
||||
|
||||
match &**args {
|
||||
GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, args),
|
||||
GenericArgs::Parenthesized(p_args) => {
|
||||
// Probe the lifetime ribs to know how to behave.
|
||||
for rib in self.lifetime_ribs.iter().rev() {
|
||||
match rib.kind {
|
||||
// We are inside a `PolyTraitRef`. The lifetimes are
|
||||
// to be introduced in that (maybe implicit) `for<>` binder.
|
||||
LifetimeRibKind::Generics {
|
||||
binder,
|
||||
kind: LifetimeBinderKind::PolyTrait,
|
||||
..
|
||||
} => {
|
||||
self.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousCreateParameter {
|
||||
binder,
|
||||
report_in_path: false,
|
||||
},
|
||||
|this| {
|
||||
this.resolve_fn_signature(
|
||||
binder,
|
||||
report_in_path: false,
|
||||
},
|
||||
|this| {
|
||||
this.resolve_fn_signature(
|
||||
binder,
|
||||
false,
|
||||
p_args.inputs.iter().map(|ty| (None, &**ty)),
|
||||
&p_args.output,
|
||||
)
|
||||
},
|
||||
);
|
||||
break;
|
||||
}
|
||||
// We have nowhere to introduce generics. Code is malformed,
|
||||
// so use regular lifetime resolution to avoid spurious errors.
|
||||
LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => {
|
||||
visit::walk_generic_args(self, args);
|
||||
break;
|
||||
}
|
||||
LifetimeRibKind::AnonymousCreateParameter { .. }
|
||||
| LifetimeRibKind::AnonymousReportError
|
||||
| LifetimeRibKind::StaticIfNoLifetimeInScope { .. }
|
||||
| LifetimeRibKind::Elided(_)
|
||||
| LifetimeRibKind::ElisionFailure
|
||||
| LifetimeRibKind::ConcreteAnonConst(_)
|
||||
| LifetimeRibKind::ConstParamTy => {}
|
||||
false,
|
||||
p_args.inputs.iter().map(|ty| (None, &**ty)),
|
||||
&p_args.output,
|
||||
)
|
||||
},
|
||||
);
|
||||
break;
|
||||
}
|
||||
// We have nowhere to introduce generics. Code is malformed,
|
||||
// so use regular lifetime resolution to avoid spurious errors.
|
||||
LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => {
|
||||
visit::walk_generic_args(self, args);
|
||||
break;
|
||||
}
|
||||
LifetimeRibKind::AnonymousCreateParameter { .. }
|
||||
| LifetimeRibKind::AnonymousReportError
|
||||
| LifetimeRibKind::StaticIfNoLifetimeInScope { .. }
|
||||
| LifetimeRibKind::Elided(_)
|
||||
| LifetimeRibKind::ElisionFailure
|
||||
| LifetimeRibKind::ConcreteAnonConst(_)
|
||||
| LifetimeRibKind::ConstParamTy => {}
|
||||
}
|
||||
}
|
||||
GenericArgs::ParenthesizedElided(_) => {}
|
||||
}
|
||||
GenericArgs::ParenthesizedElided(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1735,13 +1728,8 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
}
|
||||
|
||||
let normalized_ident = ident.normalize_to_macros_2_0();
|
||||
let mut outer_res = None;
|
||||
for rib in lifetime_rib_iter {
|
||||
if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) {
|
||||
outer_res = Some(outer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let outer_res = lifetime_rib_iter
|
||||
.find_map(|rib| rib.bindings.get_key_value(&normalized_ident).map(|(&outer, _)| outer));
|
||||
|
||||
self.emit_undeclared_lifetime_error(lifetime, outer_res);
|
||||
self.record_lifetime_res(lifetime.id, LifetimeRes::Error, LifetimeElisionCandidate::Named);
|
||||
|
@ -1808,23 +1796,21 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
}
|
||||
LifetimeRibKind::AnonymousReportError => {
|
||||
if elided {
|
||||
let mut suggestion = None;
|
||||
for rib in self.lifetime_ribs[i..].iter().rev() {
|
||||
let suggestion = self.lifetime_ribs[i..].iter().rev().find_map(|rib| {
|
||||
if let LifetimeRibKind::Generics {
|
||||
span,
|
||||
kind: LifetimeBinderKind::PolyTrait | LifetimeBinderKind::WhereBound,
|
||||
..
|
||||
} = &rib.kind
|
||||
} = rib.kind
|
||||
{
|
||||
suggestion =
|
||||
Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion {
|
||||
lo: span.shrink_to_lo(),
|
||||
hi: lifetime.ident.span.shrink_to_hi(),
|
||||
});
|
||||
break;
|
||||
Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion {
|
||||
lo: span.shrink_to_lo(),
|
||||
hi: lifetime.ident.span.shrink_to_hi(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
// are we trying to use an anonymous lifetime
|
||||
// on a non GAT associated trait type?
|
||||
if !self.in_func_body
|
||||
|
@ -2460,12 +2446,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
for i in (0..self.label_ribs.len()).rev() {
|
||||
let rib = &self.label_ribs[i];
|
||||
|
||||
if let RibKind::MacroDefinition(def) = rib.kind {
|
||||
if let RibKind::MacroDefinition(def) = rib.kind
|
||||
// If an invocation of this macro created `ident`, give up on `ident`
|
||||
// and switch to `ident`'s source from the macro definition.
|
||||
if def == self.r.macro_def(label.span.ctxt()) {
|
||||
label.span.remove_mark();
|
||||
}
|
||||
&& def == self.r.macro_def(label.span.ctxt())
|
||||
{
|
||||
label.span.remove_mark();
|
||||
}
|
||||
|
||||
let ident = label.normalize_to_macro_rules();
|
||||
|
@ -2493,14 +2479,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
/// Determine whether or not a label from the `rib_index`th label rib is reachable.
|
||||
fn is_label_valid_from_rib(&self, rib_index: usize) -> bool {
|
||||
let ribs = &self.label_ribs[rib_index + 1..];
|
||||
|
||||
for rib in ribs {
|
||||
if rib.kind.is_label_barrier() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
ribs.iter().all(|rib| !rib.kind.is_label_barrier())
|
||||
}
|
||||
|
||||
fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
|
||||
|
@ -3505,21 +3484,20 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
self.visit_ty(&qself.ty);
|
||||
}
|
||||
self.visit_path(&delegation.path, delegation.id);
|
||||
if let Some(body) = &delegation.body {
|
||||
self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
|
||||
// `PatBoundCtx` is not necessary in this context
|
||||
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
|
||||
let Some(body) = &delegation.body else { return };
|
||||
self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
|
||||
// `PatBoundCtx` is not necessary in this context
|
||||
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
|
||||
|
||||
let span = delegation.path.segments.last().unwrap().ident.span;
|
||||
this.fresh_binding(
|
||||
Ident::new(kw::SelfLower, span),
|
||||
delegation.id,
|
||||
PatternSource::FnParam,
|
||||
&mut bindings,
|
||||
);
|
||||
this.visit_block(body);
|
||||
});
|
||||
}
|
||||
let span = delegation.path.segments.last().unwrap().ident.span;
|
||||
this.fresh_binding(
|
||||
Ident::new(kw::SelfLower, span),
|
||||
delegation.id,
|
||||
PatternSource::FnParam,
|
||||
&mut bindings,
|
||||
);
|
||||
this.visit_block(body);
|
||||
});
|
||||
}
|
||||
|
||||
fn resolve_params(&mut self, params: &'ast [Param]) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue