Auto merge of #63437 - Centril:rollup-ryx881p, r=Centril
Rollup of 4 pull requests Successful merges: - #63400 (Try to break resolve into more isolated parts) - #63425 (Cleanup historical stability comments) - #63429 (.gitignore: Readd `/tmp/`) - #63432 (Cleanup & Simplify stuff in lowering) Failed merges: r? @ghost
This commit is contained in:
commit
be3fb0cd2c
20 changed files with 4498 additions and 4415 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -27,6 +27,7 @@ __pycache__/
|
|||
/inst/
|
||||
/llvm/
|
||||
/mingw-build/
|
||||
# Created by default with `src/ci/docker/run.sh`:
|
||||
/obj/
|
||||
/rustllvm/
|
||||
/src/libcore/unicode/DerivedCoreProperties.txt
|
||||
|
@ -38,6 +39,8 @@ __pycache__/
|
|||
/src/libcore/unicode/UnicodeData.txt
|
||||
/src/libcore/unicode/downloaded
|
||||
/target/
|
||||
# Generated by compiletest for incremental:
|
||||
/tmp/
|
||||
tags
|
||||
tags.*
|
||||
TAGS
|
||||
|
|
|
@ -37,7 +37,7 @@ use crate::hir::{self, ParamName};
|
|||
use crate::hir::HirVec;
|
||||
use crate::hir::map::{DefKey, DefPathData, Definitions};
|
||||
use crate::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
|
||||
use crate::hir::def::{Res, DefKind, PartialRes, PerNS};
|
||||
use crate::hir::def::{Namespace, Res, DefKind, PartialRes, PerNS};
|
||||
use crate::hir::{GenericArg, ConstArg};
|
||||
use crate::hir::ptr::P;
|
||||
use crate::lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
|
||||
|
@ -148,13 +148,6 @@ pub struct LoweringContext<'a> {
|
|||
}
|
||||
|
||||
pub trait Resolver {
|
||||
/// Resolve a path generated by the lowerer when expanding `for`, `if let`, etc.
|
||||
fn resolve_ast_path(
|
||||
&mut self,
|
||||
path: &ast::Path,
|
||||
is_value: bool,
|
||||
) -> Res<NodeId>;
|
||||
|
||||
/// Obtain resolution for a `NodeId` with a single resolution.
|
||||
fn get_partial_res(&mut self, id: NodeId) -> Option<PartialRes>;
|
||||
|
||||
|
@ -175,7 +168,7 @@ pub trait Resolver {
|
|||
span: Span,
|
||||
crate_root: Option<Symbol>,
|
||||
components: &[Symbol],
|
||||
is_value: bool,
|
||||
ns: Namespace,
|
||||
) -> (ast::Path, Res<NodeId>);
|
||||
|
||||
fn has_derives(&self, node_id: NodeId, derives: SpecialDerives) -> bool;
|
||||
|
@ -4447,23 +4440,23 @@ impl<'a> LoweringContext<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> HirVec<hir::Expr> {
|
||||
exprs.iter().map(|x| self.lower_expr(x)).collect()
|
||||
}
|
||||
|
||||
fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
|
||||
let kind = match e.node {
|
||||
ExprKind::Box(ref inner) => hir::ExprKind::Box(P(self.lower_expr(inner))),
|
||||
ExprKind::Array(ref exprs) => {
|
||||
hir::ExprKind::Array(exprs.iter().map(|x| self.lower_expr(x)).collect())
|
||||
}
|
||||
ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
|
||||
ExprKind::Repeat(ref expr, ref count) => {
|
||||
let expr = P(self.lower_expr(expr));
|
||||
let count = self.lower_anon_const(count);
|
||||
hir::ExprKind::Repeat(expr, count)
|
||||
}
|
||||
ExprKind::Tup(ref elts) => {
|
||||
hir::ExprKind::Tup(elts.iter().map(|x| self.lower_expr(x)).collect())
|
||||
}
|
||||
ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
|
||||
ExprKind::Call(ref f, ref args) => {
|
||||
let f = P(self.lower_expr(f));
|
||||
hir::ExprKind::Call(f, args.iter().map(|x| self.lower_expr(x)).collect())
|
||||
hir::ExprKind::Call(f, self.lower_exprs(args))
|
||||
}
|
||||
ExprKind::MethodCall(ref seg, ref args) => {
|
||||
let hir_seg = P(self.lower_path_segment(
|
||||
|
@ -4475,7 +4468,7 @@ impl<'a> LoweringContext<'a> {
|
|||
ImplTraitContext::disallowed(),
|
||||
None,
|
||||
));
|
||||
let args = args.iter().map(|x| self.lower_expr(x)).collect();
|
||||
let args = self.lower_exprs(args);
|
||||
hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args)
|
||||
}
|
||||
ExprKind::Binary(binop, ref lhs, ref rhs) => {
|
||||
|
@ -5049,17 +5042,9 @@ impl<'a> LoweringContext<'a> {
|
|||
));
|
||||
let arms = hir_vec![pat_arm, break_arm];
|
||||
|
||||
P(self.expr(
|
||||
head_sp,
|
||||
hir::ExprKind::Match(
|
||||
next_expr,
|
||||
arms,
|
||||
hir::MatchSource::ForLoopDesugar
|
||||
),
|
||||
ThinVec::new(),
|
||||
))
|
||||
self.expr_match(head_sp, next_expr, arms, hir::MatchSource::ForLoopDesugar)
|
||||
};
|
||||
let match_stmt = self.stmt(head_sp, hir::StmtKind::Expr(match_expr));
|
||||
let match_stmt = self.stmt_expr(head_sp, match_expr);
|
||||
|
||||
let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat_hid));
|
||||
|
||||
|
@ -5083,8 +5068,8 @@ impl<'a> LoweringContext<'a> {
|
|||
);
|
||||
|
||||
let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
|
||||
let body_expr = P(self.expr_block(body_block, ThinVec::new()));
|
||||
let body_stmt = self.stmt(body.span, hir::StmtKind::Expr(body_expr));
|
||||
let body_expr = self.expr_block(body_block, ThinVec::new());
|
||||
let body_stmt = self.stmt_expr(body.span, body_expr);
|
||||
|
||||
let loop_block = P(self.block_all(
|
||||
e.span,
|
||||
|
@ -5127,8 +5112,10 @@ impl<'a> LoweringContext<'a> {
|
|||
));
|
||||
|
||||
// This is effectively `{ let _result = ...; _result }`.
|
||||
// The construct was introduced in #21984.
|
||||
// FIXME(60253): Is this still necessary?
|
||||
// The construct was introduced in #21984 and is necessary to make sure that
|
||||
// temporaries in the `head` expression are dropped and do not leak to the
|
||||
// surrounding scope of the `match` since the `match` is not a terminating scope.
|
||||
//
|
||||
// Also, add the attributes to the outer returned expr node.
|
||||
return self.expr_drop_temps(head_sp, match_expr, e.attrs.clone())
|
||||
}
|
||||
|
@ -5254,7 +5241,7 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
|
||||
fn lower_stmt(&mut self, s: &Stmt) -> SmallVec<[hir::Stmt; 1]> {
|
||||
smallvec![match s.node {
|
||||
let node = match s.node {
|
||||
StmtKind::Local(ref l) => {
|
||||
let (l, item_ids) = self.lower_local(l);
|
||||
let mut ids: SmallVec<[hir::Stmt; 1]> = item_ids
|
||||
|
@ -5291,21 +5278,14 @@ impl<'a> LoweringContext<'a> {
|
|||
})
|
||||
.collect();
|
||||
}
|
||||
StmtKind::Expr(ref e) => {
|
||||
hir::Stmt {
|
||||
hir_id: self.lower_node_id(s.id),
|
||||
node: hir::StmtKind::Expr(P(self.lower_expr(e))),
|
||||
span: s.span,
|
||||
}
|
||||
},
|
||||
StmtKind::Semi(ref e) => {
|
||||
hir::Stmt {
|
||||
hir_id: self.lower_node_id(s.id),
|
||||
node: hir::StmtKind::Semi(P(self.lower_expr(e))),
|
||||
span: s.span,
|
||||
}
|
||||
},
|
||||
StmtKind::Expr(ref e) => hir::StmtKind::Expr(P(self.lower_expr(e))),
|
||||
StmtKind::Semi(ref e) => hir::StmtKind::Semi(P(self.lower_expr(e))),
|
||||
StmtKind::Mac(..) => panic!("Shouldn't exist here"),
|
||||
};
|
||||
smallvec![hir::Stmt {
|
||||
hir_id: self.lower_node_id(s.id),
|
||||
node,
|
||||
span: s.span,
|
||||
}]
|
||||
}
|
||||
|
||||
|
@ -5567,6 +5547,10 @@ impl<'a> LoweringContext<'a> {
|
|||
hir::Stmt { span, node, hir_id: self.next_id() }
|
||||
}
|
||||
|
||||
fn stmt_expr(&mut self, span: Span, expr: hir::Expr) -> hir::Stmt {
|
||||
self.stmt(span, hir::StmtKind::Expr(P(expr)))
|
||||
}
|
||||
|
||||
fn stmt_let_pat(
|
||||
&mut self,
|
||||
attrs: ThinVec<Attribute>,
|
||||
|
@ -5717,8 +5701,8 @@ impl<'a> LoweringContext<'a> {
|
|||
params: Option<P<hir::GenericArgs>>,
|
||||
is_value: bool,
|
||||
) -> hir::Path {
|
||||
let (path, res) = self.resolver
|
||||
.resolve_str_path(span, self.crate_root, components, is_value);
|
||||
let ns = if is_value { Namespace::ValueNS } else { Namespace::TypeNS };
|
||||
let (path, res) = self.resolver.resolve_str_path(span, self.crate_root, components, ns);
|
||||
|
||||
let mut segments: Vec<_> = path.segments.iter().map(|segment| {
|
||||
let res = self.expect_full_res(segment.id);
|
||||
|
@ -6060,23 +6044,23 @@ impl<'a> LoweringContext<'a> {
|
|||
};
|
||||
|
||||
let match_stmt = {
|
||||
let match_expr = P(self.expr_match(
|
||||
let match_expr = self.expr_match(
|
||||
span,
|
||||
poll_expr,
|
||||
hir_vec![ready_arm, pending_arm],
|
||||
hir::MatchSource::AwaitDesugar,
|
||||
));
|
||||
self.stmt(span, hir::StmtKind::Expr(match_expr))
|
||||
);
|
||||
self.stmt_expr(span, match_expr)
|
||||
};
|
||||
|
||||
let yield_stmt = {
|
||||
let unit = self.expr_unit(span);
|
||||
let yield_expr = P(self.expr(
|
||||
let yield_expr = self.expr(
|
||||
span,
|
||||
hir::ExprKind::Yield(P(unit), hir::YieldSource::Await),
|
||||
ThinVec::new(),
|
||||
));
|
||||
self.stmt(span, hir::StmtKind::Expr(yield_expr))
|
||||
);
|
||||
self.stmt_expr(span, yield_expr)
|
||||
};
|
||||
|
||||
let loop_block = P(self.block_all(
|
||||
|
|
|
@ -957,14 +957,11 @@ fn print_flag_list<T>(cmdline_opt: &str,
|
|||
/// otherwise returns `None`.
|
||||
///
|
||||
/// The compiler's handling of options is a little complicated as it ties into
|
||||
/// our stability story, and it's even *more* complicated by historical
|
||||
/// accidents. The current intention of each compiler option is to have one of
|
||||
/// three modes:
|
||||
/// our stability story. The current intention of each compiler option is to
|
||||
/// have one of two modes:
|
||||
///
|
||||
/// 1. An option is stable and can be used everywhere.
|
||||
/// 2. An option is unstable, but was historically allowed on the stable
|
||||
/// channel.
|
||||
/// 3. An option is unstable, and can only be used on nightly.
|
||||
/// 2. An option is unstable, and can only be used on nightly.
|
||||
///
|
||||
/// Like unstable library and language features, however, unstable options have
|
||||
/// always required a form of "opt in" to indicate that you're using them. This
|
||||
|
@ -1007,19 +1004,13 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
|
|||
// this option that was passed.
|
||||
// * If we're a nightly compiler, then unstable options are now unlocked, so
|
||||
// we're good to go.
|
||||
// * Otherwise, if we're a truly unstable option then we generate an error
|
||||
// * Otherwise, if we're an unstable option then we generate an error
|
||||
// (unstable option being used on stable)
|
||||
// * If we're a historically stable-but-should-be-unstable option then we
|
||||
// emit a warning that we're going to turn this into an error soon.
|
||||
nightly_options::check_nightly_options(&matches, &config::rustc_optgroups());
|
||||
|
||||
if matches.opt_present("h") || matches.opt_present("help") {
|
||||
// Only show unstable options in --help if we *really* accept unstable
|
||||
// options, which catches the case where we got `-Z unstable-options` on
|
||||
// the stable channel of Rust which was accidentally allowed
|
||||
// historically.
|
||||
usage(matches.opt_present("verbose"),
|
||||
nightly_options::is_unstable_enabled(&matches));
|
||||
// Only show unstable options in --help if we accept unstable options.
|
||||
usage(matches.opt_present("verbose"), nightly_options::is_unstable_enabled(&matches));
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -23,8 +23,6 @@
|
|||
// - `check_crate` finally emits the diagnostics based on the data generated
|
||||
// in the last step
|
||||
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::Resolver;
|
||||
use crate::resolve_imports::ImportDirectiveSubclass;
|
||||
|
||||
|
@ -49,7 +47,7 @@ impl<'a> UnusedImport<'a> {
|
|||
}
|
||||
|
||||
struct UnusedImportCheckVisitor<'a, 'b> {
|
||||
resolver: &'a mut Resolver<'b>,
|
||||
r: &'a mut Resolver<'b>,
|
||||
/// All the (so far) unused imports, grouped path list
|
||||
unused_imports: NodeMap<UnusedImport<'a>>,
|
||||
base_use_tree: Option<&'a ast::UseTree>,
|
||||
|
@ -57,29 +55,14 @@ struct UnusedImportCheckVisitor<'a, 'b> {
|
|||
item_span: Span,
|
||||
}
|
||||
|
||||
// Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver.
|
||||
impl<'a, 'b> Deref for UnusedImportCheckVisitor<'a, 'b> {
|
||||
type Target = Resolver<'b>;
|
||||
|
||||
fn deref<'c>(&'c self) -> &'c Resolver<'b> {
|
||||
&*self.resolver
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> DerefMut for UnusedImportCheckVisitor<'a, 'b> {
|
||||
fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b> {
|
||||
&mut *self.resolver
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
|
||||
// We have information about whether `use` (import) directives 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) {
|
||||
let mut used = false;
|
||||
self.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns)));
|
||||
self.r.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns)));
|
||||
if !used {
|
||||
if self.maybe_unused_trait_imports.contains(&id) {
|
||||
if self.r.maybe_unused_trait_imports.contains(&id) {
|
||||
// Check later.
|
||||
return;
|
||||
}
|
||||
|
@ -87,7 +70,7 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
|
|||
} else {
|
||||
// This trait import is definitely used, in a way other than
|
||||
// method resolution.
|
||||
self.maybe_unused_trait_imports.remove(&id);
|
||||
self.r.maybe_unused_trait_imports.remove(&id);
|
||||
if let Some(i) = self.unused_imports.get_mut(&self.base_id) {
|
||||
i.unused.remove(&id);
|
||||
}
|
||||
|
@ -238,104 +221,102 @@ fn calc_unused_spans(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn check_crate(resolver: &mut Resolver<'_>, krate: &ast::Crate) {
|
||||
for directive in resolver.potentially_unused_imports.iter() {
|
||||
match directive.subclass {
|
||||
_ if directive.used.get() ||
|
||||
directive.vis.get() == ty::Visibility::Public ||
|
||||
directive.span.is_dummy() => {
|
||||
if let ImportDirectiveSubclass::MacroUse = directive.subclass {
|
||||
if !directive.span.is_dummy() {
|
||||
resolver.session.buffer_lint(
|
||||
lint::builtin::MACRO_USE_EXTERN_CRATE,
|
||||
directive.id,
|
||||
directive.span,
|
||||
"deprecated `#[macro_use]` directive used to \
|
||||
import macros should be replaced at use sites \
|
||||
with a `use` statement to import the macro \
|
||||
instead",
|
||||
);
|
||||
impl Resolver<'_> {
|
||||
crate fn check_unused(&mut self, krate: &ast::Crate) {
|
||||
for directive in self.potentially_unused_imports.iter() {
|
||||
match directive.subclass {
|
||||
_ if directive.used.get() ||
|
||||
directive.vis.get() == ty::Visibility::Public ||
|
||||
directive.span.is_dummy() => {
|
||||
if let ImportDirectiveSubclass::MacroUse = directive.subclass {
|
||||
if !directive.span.is_dummy() {
|
||||
self.session.buffer_lint(
|
||||
lint::builtin::MACRO_USE_EXTERN_CRATE,
|
||||
directive.id,
|
||||
directive.span,
|
||||
"deprecated `#[macro_use]` directive used to \
|
||||
import macros should be replaced at use sites \
|
||||
with a `use` statement to import the macro \
|
||||
instead",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImportDirectiveSubclass::ExternCrate { .. } => {
|
||||
self.maybe_unused_extern_crates.push((directive.id, directive.span));
|
||||
}
|
||||
ImportDirectiveSubclass::MacroUse => {
|
||||
let lint = lint::builtin::UNUSED_IMPORTS;
|
||||
let msg = "unused `#[macro_use]` import";
|
||||
self.session.buffer_lint(lint, directive.id, directive.span, msg);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
ImportDirectiveSubclass::ExternCrate { .. } => {
|
||||
resolver.maybe_unused_extern_crates.push((directive.id, directive.span));
|
||||
}
|
||||
ImportDirectiveSubclass::MacroUse => {
|
||||
let lint = lint::builtin::UNUSED_IMPORTS;
|
||||
let msg = "unused `#[macro_use]` import";
|
||||
resolver.session.buffer_lint(lint, directive.id, directive.span, msg);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let mut visitor = UnusedImportCheckVisitor {
|
||||
r: self,
|
||||
unused_imports: Default::default(),
|
||||
base_use_tree: None,
|
||||
base_id: ast::DUMMY_NODE_ID,
|
||||
item_span: DUMMY_SP,
|
||||
};
|
||||
visit::walk_crate(&mut visitor, krate);
|
||||
|
||||
for unused in visitor.unused_imports.values() {
|
||||
let mut fixes = Vec::new();
|
||||
let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
|
||||
UnusedSpanResult::Used => continue,
|
||||
UnusedSpanResult::FlatUnused(span, remove) => {
|
||||
fixes.push((remove, String::new()));
|
||||
vec![span]
|
||||
}
|
||||
UnusedSpanResult::NestedFullUnused(spans, remove) => {
|
||||
fixes.push((remove, String::new()));
|
||||
spans
|
||||
}
|
||||
UnusedSpanResult::NestedPartialUnused(spans, remove) => {
|
||||
for fix in &remove {
|
||||
fixes.push((*fix, String::new()));
|
||||
}
|
||||
spans
|
||||
}
|
||||
};
|
||||
|
||||
let len = spans.len();
|
||||
spans.sort();
|
||||
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) {
|
||||
Ok(s) => Some(format!("`{}`", s)),
|
||||
_ => None,
|
||||
}
|
||||
}).collect::<Vec<String>>();
|
||||
span_snippets.sort();
|
||||
let msg = format!("unused import{}{}",
|
||||
if len > 1 { "s" } else { "" },
|
||||
if !span_snippets.is_empty() {
|
||||
format!(": {}", span_snippets.join(", "))
|
||||
} else {
|
||||
String::new()
|
||||
});
|
||||
|
||||
let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span {
|
||||
"remove the whole `use` item"
|
||||
} else if spans.len() > 1 {
|
||||
"remove the unused imports"
|
||||
} else {
|
||||
"remove the unused import"
|
||||
};
|
||||
|
||||
visitor.r.session.buffer_lint_with_diagnostic(
|
||||
lint::builtin::UNUSED_IMPORTS,
|
||||
unused.use_tree_id,
|
||||
ms,
|
||||
&msg,
|
||||
lint::builtin::BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (id, span) in resolver.unused_labels.iter() {
|
||||
resolver.session.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label");
|
||||
}
|
||||
|
||||
let mut visitor = UnusedImportCheckVisitor {
|
||||
resolver,
|
||||
unused_imports: Default::default(),
|
||||
base_use_tree: None,
|
||||
base_id: ast::DUMMY_NODE_ID,
|
||||
item_span: DUMMY_SP,
|
||||
};
|
||||
visit::walk_crate(&mut visitor, krate);
|
||||
|
||||
for unused in visitor.unused_imports.values() {
|
||||
let mut fixes = Vec::new();
|
||||
let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
|
||||
UnusedSpanResult::Used => continue,
|
||||
UnusedSpanResult::FlatUnused(span, remove) => {
|
||||
fixes.push((remove, String::new()));
|
||||
vec![span]
|
||||
}
|
||||
UnusedSpanResult::NestedFullUnused(spans, remove) => {
|
||||
fixes.push((remove, String::new()));
|
||||
spans
|
||||
}
|
||||
UnusedSpanResult::NestedPartialUnused(spans, remove) => {
|
||||
for fix in &remove {
|
||||
fixes.push((*fix, String::new()));
|
||||
}
|
||||
spans
|
||||
}
|
||||
};
|
||||
|
||||
let len = spans.len();
|
||||
spans.sort();
|
||||
let ms = MultiSpan::from_spans(spans.clone());
|
||||
let mut span_snippets = spans.iter()
|
||||
.filter_map(|s| {
|
||||
match visitor.session.source_map().span_to_snippet(*s) {
|
||||
Ok(s) => Some(format!("`{}`", s)),
|
||||
_ => None,
|
||||
}
|
||||
}).collect::<Vec<String>>();
|
||||
span_snippets.sort();
|
||||
let msg = format!("unused import{}{}",
|
||||
if len > 1 { "s" } else { "" },
|
||||
if !span_snippets.is_empty() {
|
||||
format!(": {}", span_snippets.join(", "))
|
||||
} else {
|
||||
String::new()
|
||||
});
|
||||
|
||||
let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span {
|
||||
"remove the whole `use` item"
|
||||
} else if spans.len() > 1 {
|
||||
"remove the unused imports"
|
||||
} else {
|
||||
"remove the unused import"
|
||||
};
|
||||
|
||||
visitor.session.buffer_lint_with_diagnostic(
|
||||
lint::builtin::UNUSED_IMPORTS,
|
||||
unused.use_tree_id,
|
||||
ms,
|
||||
&msg,
|
||||
lint::builtin::BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
2004
src/librustc_resolve/late.rs
Normal file
2004
src/librustc_resolve/late.rs
Normal file
File diff suppressed because it is too large
Load diff
770
src/librustc_resolve/late/diagnostics.rs
Normal file
770
src/librustc_resolve/late/diagnostics.rs
Normal file
|
@ -0,0 +1,770 @@
|
|||
use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot};
|
||||
use crate::{PathResult, PathSource, Segment};
|
||||
use crate::path_names_to_string;
|
||||
use crate::diagnostics::{add_typo_suggestion, add_module_candidates};
|
||||
use crate::diagnostics::{ImportSuggestion, TypoSuggestion};
|
||||
use crate::late::{LateResolutionVisitor, RibKind};
|
||||
|
||||
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
|
||||
use log::debug;
|
||||
use rustc::hir::def::{self, DefKind, CtorKind};
|
||||
use rustc::hir::def::Namespace::{self, *};
|
||||
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
|
||||
use rustc::hir::PrimTy;
|
||||
use rustc::session::config::nightly_options;
|
||||
use rustc::util::nodemap::FxHashSet;
|
||||
use syntax::ast::{self, Expr, ExprKind, Ident, NodeId, Path, Ty, TyKind};
|
||||
use syntax::ext::base::MacroKind;
|
||||
use syntax::symbol::kw;
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
use syntax_pos::Span;
|
||||
|
||||
type Res = def::Res<ast::NodeId>;
|
||||
|
||||
/// A field or associated item from self type suggested in case of resolution failure.
|
||||
enum AssocSuggestion {
|
||||
Field,
|
||||
MethodWithSelf,
|
||||
AssocItem,
|
||||
}
|
||||
|
||||
fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {
|
||||
namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper
|
||||
}
|
||||
|
||||
fn is_self_value(path: &[Segment], namespace: Namespace) -> bool {
|
||||
namespace == ValueNS && path.len() == 1 && path[0].ident.name == kw::SelfLower
|
||||
}
|
||||
|
||||
/// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.
|
||||
fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) {
|
||||
let variant_path = &suggestion.path;
|
||||
let variant_path_string = path_names_to_string(variant_path);
|
||||
|
||||
let path_len = suggestion.path.segments.len();
|
||||
let enum_path = ast::Path {
|
||||
span: suggestion.path.span,
|
||||
segments: suggestion.path.segments[0..path_len - 1].to_vec(),
|
||||
};
|
||||
let enum_path_string = path_names_to_string(&enum_path);
|
||||
|
||||
(variant_path_string, enum_path_string)
|
||||
}
|
||||
|
||||
impl<'a> LateResolutionVisitor<'a, '_> {
|
||||
/// Handles error reporting for `smart_resolve_path_fragment` function.
|
||||
/// Creates base error and amends it with one short label and possibly some longer helps/notes.
|
||||
pub(crate) fn smart_resolve_report_errors(
|
||||
&mut self,
|
||||
path: &[Segment],
|
||||
span: Span,
|
||||
source: PathSource<'_>,
|
||||
res: Option<Res>,
|
||||
) -> (DiagnosticBuilder<'a>, Vec<ImportSuggestion>) {
|
||||
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
|
||||
let ns = source.namespace();
|
||||
let is_expected = &|res| source.is_expected(res);
|
||||
let is_enum_variant = &|res| {
|
||||
if let Res::Def(DefKind::Variant, _) = res { true } else { false }
|
||||
};
|
||||
|
||||
// Make the base error.
|
||||
let expected = source.descr_expected();
|
||||
let path_str = Segment::names_to_string(path);
|
||||
let item_str = path.last().unwrap().ident;
|
||||
let code = source.error_code(res.is_some());
|
||||
let (base_msg, fallback_label, base_span) = if let Some(res) = res {
|
||||
(format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
|
||||
format!("not a {}", expected),
|
||||
span)
|
||||
} else {
|
||||
let item_span = path.last().unwrap().ident.span;
|
||||
let (mod_prefix, mod_str) = if path.len() == 1 {
|
||||
(String::new(), "this scope".to_string())
|
||||
} else if path.len() == 2 && path[0].ident.name == kw::PathRoot {
|
||||
(String::new(), "the crate root".to_string())
|
||||
} else {
|
||||
let mod_path = &path[..path.len() - 1];
|
||||
let mod_prefix = match self.resolve_path(
|
||||
mod_path, Some(TypeNS), false, span, CrateLint::No
|
||||
) {
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
|
||||
module.def_kind(),
|
||||
_ => None,
|
||||
}.map_or(String::new(), |kind| format!("{} ", kind.descr()));
|
||||
(mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)))
|
||||
};
|
||||
(format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
|
||||
format!("not found in {}", mod_str),
|
||||
item_span)
|
||||
};
|
||||
|
||||
let code = DiagnosticId::Error(code.into());
|
||||
let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code);
|
||||
|
||||
// Emit help message for fake-self from other languages (e.g., `this` in Javascript).
|
||||
if ["this", "my"].contains(&&*item_str.as_str())
|
||||
&& self.self_value_is_available(path[0].ident.span, span) {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"did you mean",
|
||||
"self".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
// Emit special messages for unresolved `Self` and `self`.
|
||||
if is_self_type(path, ns) {
|
||||
__diagnostic_used!(E0411);
|
||||
err.code(DiagnosticId::Error("E0411".into()));
|
||||
err.span_label(span, format!("`Self` is only available in impls, traits, \
|
||||
and type definitions"));
|
||||
return (err, Vec::new());
|
||||
}
|
||||
if is_self_value(path, ns) {
|
||||
debug!("smart_resolve_path_fragment: E0424, source={:?}", source);
|
||||
|
||||
__diagnostic_used!(E0424);
|
||||
err.code(DiagnosticId::Error("E0424".into()));
|
||||
err.span_label(span, match source {
|
||||
PathSource::Pat => {
|
||||
format!("`self` value is a keyword \
|
||||
and may not be bound to \
|
||||
variables or shadowed")
|
||||
}
|
||||
_ => {
|
||||
format!("`self` value is a keyword \
|
||||
only available in methods \
|
||||
with `self` parameter")
|
||||
}
|
||||
});
|
||||
return (err, Vec::new());
|
||||
}
|
||||
|
||||
// Try to lookup name in more relaxed fashion for better error reporting.
|
||||
let ident = path.last().unwrap().ident;
|
||||
let candidates = self.r.lookup_import_candidates(ident, ns, is_expected)
|
||||
.drain(..)
|
||||
.filter(|ImportSuggestion { did, .. }| {
|
||||
match (did, res.and_then(|res| res.opt_def_id())) {
|
||||
(Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,
|
||||
_ => true,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let crate_def_id = DefId::local(CRATE_DEF_INDEX);
|
||||
if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
|
||||
let enum_candidates =
|
||||
self.r.lookup_import_candidates(ident, ns, is_enum_variant);
|
||||
let mut enum_candidates = enum_candidates.iter()
|
||||
.map(|suggestion| {
|
||||
import_candidate_to_enum_paths(&suggestion)
|
||||
}).collect::<Vec<_>>();
|
||||
enum_candidates.sort();
|
||||
|
||||
if !enum_candidates.is_empty() {
|
||||
// Contextualize for E0412 "cannot find type", but don't belabor the point
|
||||
// (that it's a variant) for E0573 "expected type, found variant".
|
||||
let preamble = if res.is_none() {
|
||||
let others = match enum_candidates.len() {
|
||||
1 => String::new(),
|
||||
2 => " and 1 other".to_owned(),
|
||||
n => format!(" and {} others", n)
|
||||
};
|
||||
format!("there is an enum variant `{}`{}; ",
|
||||
enum_candidates[0].0, others)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
let msg = format!("{}try using the variant's enum", preamble);
|
||||
|
||||
err.span_suggestions(
|
||||
span,
|
||||
&msg,
|
||||
enum_candidates.into_iter()
|
||||
.map(|(_variant_path, enum_ty_path)| enum_ty_path)
|
||||
// Variants re-exported in prelude doesn't mean `prelude::v1` is the
|
||||
// type name!
|
||||
// FIXME: is there a more principled way to do this that
|
||||
// would work for other re-exports?
|
||||
.filter(|enum_ty_path| enum_ty_path != "std::prelude::v1")
|
||||
// Also write `Option` rather than `std::prelude::v1::Option`.
|
||||
.map(|enum_ty_path| {
|
||||
// FIXME #56861: DRY-er prelude filtering.
|
||||
enum_ty_path.trim_start_matches("std::prelude::v1::").to_owned()
|
||||
}),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
if path.len() == 1 && self.self_type_is_available(span) {
|
||||
if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) {
|
||||
let self_is_available = self.self_value_is_available(path[0].ident.span, span);
|
||||
match candidate {
|
||||
AssocSuggestion::Field => {
|
||||
if self_is_available {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"you might have meant to use the available field",
|
||||
format!("self.{}", path_str),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
err.span_label(
|
||||
span,
|
||||
"a field by this name exists in `Self`",
|
||||
);
|
||||
}
|
||||
}
|
||||
AssocSuggestion::MethodWithSelf if self_is_available => {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"try",
|
||||
format!("self.{}", path_str),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"try",
|
||||
format!("Self::{}", path_str),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
return (err, candidates);
|
||||
}
|
||||
}
|
||||
|
||||
// Try Levenshtein algorithm.
|
||||
let levenshtein_worked = add_typo_suggestion(
|
||||
&mut err, self.lookup_typo_candidate(path, ns, is_expected, span), ident_span
|
||||
);
|
||||
|
||||
// Try context-dependent help if relaxed lookup didn't work.
|
||||
if let Some(res) = res {
|
||||
if self.smart_resolve_context_dependent_help(&mut err,
|
||||
span,
|
||||
source,
|
||||
res,
|
||||
&path_str,
|
||||
&fallback_label) {
|
||||
return (err, candidates);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback label.
|
||||
if !levenshtein_worked {
|
||||
err.span_label(base_span, fallback_label);
|
||||
self.type_ascription_suggestion(&mut err, base_span);
|
||||
}
|
||||
(err, candidates)
|
||||
}
|
||||
|
||||
fn followed_by_brace(&self, span: Span) -> (bool, Option<(Span, String)>) {
|
||||
// HACK(estebank): find a better way to figure out that this was a
|
||||
// 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 mut sp = span;
|
||||
loop {
|
||||
sp = sm.next_point(sp);
|
||||
match sm.span_to_snippet(sp) {
|
||||
Ok(ref snippet) => {
|
||||
if snippet.chars().any(|c| { !c.is_whitespace() }) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
let followed_by_brace = match sm.span_to_snippet(sp) {
|
||||
Ok(ref snippet) if snippet == "{" => true,
|
||||
_ => false,
|
||||
};
|
||||
// In case this could be a struct literal that needs to be surrounded
|
||||
// by parenthesis, find the appropriate span.
|
||||
let mut i = 0;
|
||||
let mut closing_brace = None;
|
||||
loop {
|
||||
sp = sm.next_point(sp);
|
||||
match sm.span_to_snippet(sp) {
|
||||
Ok(ref snippet) => {
|
||||
if snippet == "}" {
|
||||
let sp = span.to(sp);
|
||||
if let Ok(snippet) = sm.span_to_snippet(sp) {
|
||||
closing_brace = Some((sp, snippet));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
i += 1;
|
||||
// The bigger the span, the more likely we're incorrect --
|
||||
// bound it to 100 chars long.
|
||||
if i > 100 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (followed_by_brace, closing_brace)
|
||||
}
|
||||
|
||||
/// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
|
||||
/// function.
|
||||
/// Returns `true` if able to provide context-dependent help.
|
||||
fn smart_resolve_context_dependent_help(
|
||||
&mut self,
|
||||
err: &mut DiagnosticBuilder<'a>,
|
||||
span: Span,
|
||||
source: PathSource<'_>,
|
||||
res: Res,
|
||||
path_str: &str,
|
||||
fallback_label: &str,
|
||||
) -> bool {
|
||||
let ns = source.namespace();
|
||||
let is_expected = &|res| source.is_expected(res);
|
||||
|
||||
let path_sep = |err: &mut DiagnosticBuilder<'_>, expr: &Expr| match expr.node {
|
||||
ExprKind::Field(_, ident) => {
|
||||
err.span_suggestion(
|
||||
expr.span,
|
||||
"use the path separator to refer to an item",
|
||||
format!("{}::{}", path_str, ident),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
true
|
||||
}
|
||||
ExprKind::MethodCall(ref segment, ..) => {
|
||||
let span = expr.span.with_hi(segment.ident.span.hi());
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"use the path separator to refer to an item",
|
||||
format!("{}::{}", path_str, segment.ident),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let mut bad_struct_syntax_suggestion = || {
|
||||
let (followed_by_brace, closing_brace) = self.followed_by_brace(span);
|
||||
let mut suggested = false;
|
||||
match source {
|
||||
PathSource::Expr(Some(parent)) => {
|
||||
suggested = path_sep(err, &parent);
|
||||
}
|
||||
PathSource::Expr(None) if followed_by_brace == true => {
|
||||
if let Some((sp, snippet)) = closing_brace {
|
||||
err.span_suggestion(
|
||||
sp,
|
||||
"surround the struct literal with parenthesis",
|
||||
format!("({})", snippet),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.span_label(
|
||||
span, // Note the parenthesis surrounding the suggestion below
|
||||
format!("did you mean `({} {{ /* fields */ }})`?", path_str),
|
||||
);
|
||||
}
|
||||
suggested = true;
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
if !suggested {
|
||||
err.span_label(
|
||||
span,
|
||||
format!("did you mean `{} {{ /* fields */ }}`?", path_str),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
match (res, source) {
|
||||
(Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"use `!` to invoke the macro",
|
||||
format!("{}!", path_str),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
if path_str == "try" && span.rust_2015() {
|
||||
err.note("if you want the `try` keyword, you need to be in the 2018 edition");
|
||||
}
|
||||
}
|
||||
(Res::Def(DefKind::TyAlias, _), PathSource::Trait(_)) => {
|
||||
err.span_label(span, "type aliases cannot be used as traits");
|
||||
if nightly_options::is_nightly_build() {
|
||||
err.note("did you mean to use a trait alias?");
|
||||
}
|
||||
}
|
||||
(Res::Def(DefKind::Mod, _), PathSource::Expr(Some(parent))) => {
|
||||
if !path_sep(err, &parent) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
(Res::Def(DefKind::Enum, def_id), PathSource::TupleStruct)
|
||||
| (Res::Def(DefKind::Enum, def_id), PathSource::Expr(..)) => {
|
||||
if let Some(variants) = self.collect_enum_variants(def_id) {
|
||||
if !variants.is_empty() {
|
||||
let msg = if variants.len() == 1 {
|
||||
"try using the enum's variant"
|
||||
} else {
|
||||
"try using one of the enum's variants"
|
||||
};
|
||||
|
||||
err.span_suggestions(
|
||||
span,
|
||||
msg,
|
||||
variants.iter().map(path_names_to_string),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
err.note("did you mean to use one of the enum's variants?");
|
||||
}
|
||||
},
|
||||
(Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => {
|
||||
if let Some((ctor_def, ctor_vis))
|
||||
= self.r.struct_constructors.get(&def_id).cloned() {
|
||||
let accessible_ctor =
|
||||
self.r.is_accessible_from(ctor_vis, self.parent_scope.module);
|
||||
if is_expected(ctor_def) && !accessible_ctor {
|
||||
err.span_label(
|
||||
span,
|
||||
format!("constructor is not visible here due to private fields"),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
bad_struct_syntax_suggestion();
|
||||
}
|
||||
}
|
||||
(Res::Def(DefKind::Union, _), _) |
|
||||
(Res::Def(DefKind::Variant, _), _) |
|
||||
(Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _), _) if ns == ValueNS => {
|
||||
bad_struct_syntax_suggestion();
|
||||
}
|
||||
(Res::SelfTy(..), _) if ns == ValueNS => {
|
||||
err.span_label(span, fallback_label);
|
||||
err.note("can't use `Self` as a constructor, you must use the implemented struct");
|
||||
}
|
||||
(Res::Def(DefKind::TyAlias, _), _)
|
||||
| (Res::Def(DefKind::AssocTy, _), _) if ns == ValueNS => {
|
||||
err.note("can't use a type alias as a constructor");
|
||||
}
|
||||
_ => return false,
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn lookup_assoc_candidate<FilterFn>(&mut self,
|
||||
ident: Ident,
|
||||
ns: Namespace,
|
||||
filter_fn: FilterFn)
|
||||
-> Option<AssocSuggestion>
|
||||
where FilterFn: Fn(Res) -> bool
|
||||
{
|
||||
fn extract_node_id(t: &Ty) -> Option<NodeId> {
|
||||
match t.node {
|
||||
TyKind::Path(None, _) => Some(t.id),
|
||||
TyKind::Rptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty),
|
||||
// This doesn't handle the remaining `Ty` variants as they are not
|
||||
// that commonly the self_type, it might be interesting to provide
|
||||
// support for those in future.
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// Fields are generally expected in the same contexts as locals.
|
||||
if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) {
|
||||
if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) {
|
||||
// Look for a field with the same name in the current self_type.
|
||||
if let Some(resolution) = self.r.partial_res_map.get(&node_id) {
|
||||
match resolution.base_res() {
|
||||
Res::Def(DefKind::Struct, did) | Res::Def(DefKind::Union, did)
|
||||
if resolution.unresolved_segments() == 0 => {
|
||||
if let Some(field_names) = self.r.field_names.get(&did) {
|
||||
if field_names.iter().any(|&field_name| ident.name == field_name) {
|
||||
return Some(AssocSuggestion::Field);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for assoc_type_ident in &self.current_trait_assoc_types {
|
||||
if *assoc_type_ident == ident {
|
||||
return Some(AssocSuggestion::AssocItem);
|
||||
}
|
||||
}
|
||||
|
||||
// Look for associated items in the current trait.
|
||||
if let Some((module, _)) = self.current_trait_ref {
|
||||
if let Ok(binding) = self.r.resolve_ident_in_module(
|
||||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
ns,
|
||||
&self.parent_scope,
|
||||
false,
|
||||
module.span,
|
||||
) {
|
||||
let res = binding.res();
|
||||
if filter_fn(res) {
|
||||
return Some(if self.r.has_self.contains(&res.def_id()) {
|
||||
AssocSuggestion::MethodWithSelf
|
||||
} else {
|
||||
AssocSuggestion::AssocItem
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn lookup_typo_candidate(
|
||||
&mut self,
|
||||
path: &[Segment],
|
||||
ns: Namespace,
|
||||
filter_fn: &impl Fn(Res) -> bool,
|
||||
span: Span,
|
||||
) -> Option<TypoSuggestion> {
|
||||
let mut names = Vec::new();
|
||||
if path.len() == 1 {
|
||||
// Search in lexical scope.
|
||||
// Walk backwards up the ribs in scope and collect candidates.
|
||||
for rib in self.ribs[ns].iter().rev() {
|
||||
// Locals and type parameters
|
||||
for (ident, &res) in &rib.bindings {
|
||||
if filter_fn(res) {
|
||||
names.push(TypoSuggestion::from_res(ident.name, res));
|
||||
}
|
||||
}
|
||||
// Items in scope
|
||||
if let RibKind::ModuleRibKind(module) = rib.kind {
|
||||
// Items from this module
|
||||
add_module_candidates(module, &mut names, &filter_fn);
|
||||
|
||||
if let ModuleKind::Block(..) = module.kind {
|
||||
// We can see through blocks
|
||||
} else {
|
||||
// Items from the prelude
|
||||
if !module.no_implicit_prelude {
|
||||
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, ident.span)
|
||||
.and_then(|crate_id| {
|
||||
let crate_mod = Res::Def(
|
||||
DefKind::Mod,
|
||||
DefId {
|
||||
krate: crate_id,
|
||||
index: CRATE_DEF_INDEX,
|
||||
},
|
||||
);
|
||||
|
||||
if filter_fn(crate_mod) {
|
||||
Some(TypoSuggestion::from_res(ident.name, crate_mod))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}));
|
||||
|
||||
if let Some(prelude) = self.r.prelude {
|
||||
add_module_candidates(prelude, &mut names, &filter_fn);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add primitive types to the mix
|
||||
if filter_fn(Res::PrimTy(PrimTy::Bool)) {
|
||||
names.extend(
|
||||
self.r.primitive_type_table.primitive_types.iter().map(|(name, prim_ty)| {
|
||||
TypoSuggestion::from_res(*name, Res::PrimTy(*prim_ty))
|
||||
})
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// Search in module.
|
||||
let mod_path = &path[..path.len() - 1];
|
||||
if let PathResult::Module(module) = self.resolve_path(
|
||||
mod_path, Some(TypeNS), false, span, CrateLint::No
|
||||
) {
|
||||
if let ModuleOrUniformRoot::Module(module) = module {
|
||||
add_module_candidates(module, &mut names, &filter_fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let name = path[path.len() - 1].ident.name;
|
||||
// Make sure error reporting is deterministic.
|
||||
names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str());
|
||||
|
||||
match find_best_match_for_name(
|
||||
names.iter().map(|suggestion| &suggestion.candidate),
|
||||
&name.as_str(),
|
||||
None,
|
||||
) {
|
||||
Some(found) if found != name => names
|
||||
.into_iter()
|
||||
.find(|suggestion| suggestion.candidate == found),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Only used in a specific case of type ascription suggestions
|
||||
fn get_colon_suggestion_span(&self, start: Span) -> Span {
|
||||
let cm = self.r.session.source_map();
|
||||
start.to(cm.next_point(start))
|
||||
}
|
||||
|
||||
fn type_ascription_suggestion(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
base_span: Span,
|
||||
) {
|
||||
debug!("type_ascription_suggetion {:?}", base_span);
|
||||
let cm = self.r.session.source_map();
|
||||
let base_snippet = cm.span_to_snippet(base_span);
|
||||
debug!("self.current_type_ascription {:?}", self.current_type_ascription);
|
||||
if let Some(sp) = self.current_type_ascription.last() {
|
||||
let mut sp = *sp;
|
||||
loop {
|
||||
// Try to find the `:`; bail on first non-':' / non-whitespace.
|
||||
sp = cm.next_point(sp);
|
||||
if let Ok(snippet) = cm.span_to_snippet(sp.to(cm.next_point(sp))) {
|
||||
let line_sp = cm.lookup_char_pos(sp.hi()).line;
|
||||
let line_base_sp = cm.lookup_char_pos(base_span.lo()).line;
|
||||
if snippet == ":" {
|
||||
let mut show_label = true;
|
||||
if line_sp != line_base_sp {
|
||||
err.span_suggestion_short(
|
||||
sp,
|
||||
"did you mean to use `;` here instead?",
|
||||
";".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
let colon_sp = self.get_colon_suggestion_span(sp);
|
||||
let after_colon_sp = self.get_colon_suggestion_span(
|
||||
colon_sp.shrink_to_hi(),
|
||||
);
|
||||
if !cm.span_to_snippet(after_colon_sp).map(|s| s == " ")
|
||||
.unwrap_or(false)
|
||||
{
|
||||
err.span_suggestion(
|
||||
colon_sp,
|
||||
"maybe you meant to write a path separator here",
|
||||
"::".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
show_label = false;
|
||||
}
|
||||
if let Ok(base_snippet) = base_snippet {
|
||||
let mut sp = after_colon_sp;
|
||||
for _ in 0..100 {
|
||||
// Try to find an assignment
|
||||
sp = cm.next_point(sp);
|
||||
let snippet = cm.span_to_snippet(sp.to(cm.next_point(sp)));
|
||||
match snippet {
|
||||
Ok(ref x) if x.as_str() == "=" => {
|
||||
err.span_suggestion(
|
||||
base_span,
|
||||
"maybe you meant to write an assignment here",
|
||||
format!("let {}", base_snippet),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
show_label = false;
|
||||
break;
|
||||
}
|
||||
Ok(ref x) if x.as_str() == "\n" => break,
|
||||
Err(_) => break,
|
||||
Ok(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if show_label {
|
||||
err.span_label(base_span,
|
||||
"expecting a type here because of type ascription");
|
||||
}
|
||||
break;
|
||||
} else if !snippet.trim().is_empty() {
|
||||
debug!("tried to find type ascription `:` token, couldn't find it");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {
|
||||
let mut result = None;
|
||||
let mut seen_modules = FxHashSet::default();
|
||||
let mut worklist = vec![(self.r.graph_root, Vec::new())];
|
||||
|
||||
while let Some((in_module, path_segments)) = worklist.pop() {
|
||||
// abort if the module is already found
|
||||
if result.is_some() { break; }
|
||||
|
||||
self.r.populate_module_if_necessary(in_module);
|
||||
|
||||
in_module.for_each_child_stable(|ident, _, name_binding| {
|
||||
// abort if the module is already found or if name_binding is private external
|
||||
if result.is_some() || !name_binding.vis.is_visible_locally() {
|
||||
return
|
||||
}
|
||||
if let Some(module) = name_binding.module() {
|
||||
// form the path
|
||||
let mut path_segments = path_segments.clone();
|
||||
path_segments.push(ast::PathSegment::from_ident(ident));
|
||||
let module_def_id = module.def_id().unwrap();
|
||||
if module_def_id == def_id {
|
||||
let path = Path {
|
||||
span: name_binding.span,
|
||||
segments: path_segments,
|
||||
};
|
||||
result = Some((module, ImportSuggestion { did: Some(def_id), path }));
|
||||
} else {
|
||||
// add the module to the lookup
|
||||
if seen_modules.insert(module_def_id) {
|
||||
worklist.push((module, path_segments));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn collect_enum_variants(&mut self, def_id: DefId) -> Option<Vec<Path>> {
|
||||
self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
|
||||
self.r.populate_module_if_necessary(enum_module);
|
||||
|
||||
let mut variants = Vec::new();
|
||||
enum_module.for_each_child_stable(|ident, _, name_binding| {
|
||||
if let Res::Def(DefKind::Variant, _) = name_binding.res() {
|
||||
let mut segms = enum_import_suggestion.path.segments.clone();
|
||||
segms.push(ast::PathSegment::from_ident(ident));
|
||||
variants.push(Path {
|
||||
span: name_binding.span,
|
||||
segments: segms,
|
||||
});
|
||||
}
|
||||
});
|
||||
variants
|
||||
})
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,18 +1,16 @@
|
|||
use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc, Determinacy};
|
||||
use crate::{CrateLint, Resolver, ResolutionError, Scope, ScopeSet, ParentScope, Weak};
|
||||
use crate::{Module, ModuleKind, NameBinding, PathResult, Segment, ToNameBinding};
|
||||
use crate::{resolve_error, KNOWN_TOOLS};
|
||||
use crate::ModuleOrUniformRoot;
|
||||
use crate::{ModuleOrUniformRoot, KNOWN_TOOLS};
|
||||
use crate::Namespace::*;
|
||||
use crate::build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
|
||||
use crate::build_reduced_graph::BuildReducedGraphVisitor;
|
||||
use crate::resolve_imports::ImportResolver;
|
||||
use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
|
||||
use rustc::hir::def::{self, DefKind, NonMacroAttrKind};
|
||||
use rustc::hir::map::DefCollector;
|
||||
use rustc::middle::stability;
|
||||
use rustc::{ty, lint, span_bug};
|
||||
use syntax::ast::{self, Ident, ItemKind};
|
||||
use syntax::attr::{self, StabilityLevel};
|
||||
use syntax::ast::{self, Ident};
|
||||
use syntax::attr::StabilityLevel;
|
||||
use syntax::edition::Edition;
|
||||
use syntax::ext::base::{self, Indeterminate, SpecialDerives};
|
||||
use syntax::ext::base::{MacroKind, SyntaxExtension};
|
||||
|
@ -116,21 +114,6 @@ fn fast_print_path(path: &ast::Path) -> Symbol {
|
|||
}
|
||||
}
|
||||
|
||||
fn proc_macro_stub(item: &ast::Item) -> Option<(MacroKind, Ident, Span)> {
|
||||
if attr::contains_name(&item.attrs, sym::proc_macro) {
|
||||
return Some((MacroKind::Bang, item.ident, item.span));
|
||||
} else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) {
|
||||
return Some((MacroKind::Attr, item.ident, item.span));
|
||||
} else if let Some(attr) = attr::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() {
|
||||
return Some((MacroKind::Derive, ident, ident.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
impl<'a> base::Resolver for Resolver<'a> {
|
||||
fn next_node_id(&mut self) -> ast::NodeId {
|
||||
self.session.next_node_id()
|
||||
|
@ -166,21 +149,24 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||
fragment.visit_with(&mut DefCollector::new(&mut self.definitions, expn_id));
|
||||
|
||||
let invocation = self.invocations[&expn_id];
|
||||
self.current_module = invocation.module;
|
||||
self.current_module.unresolved_invocations.borrow_mut().remove(&expn_id);
|
||||
self.current_module.unresolved_invocations.borrow_mut().extend(derives);
|
||||
invocation.module.unresolved_invocations.borrow_mut().remove(&expn_id);
|
||||
invocation.module.unresolved_invocations.borrow_mut().extend(derives);
|
||||
let parent_def = self.definitions.invocation_parent(expn_id);
|
||||
for &derive_invoc_id in derives {
|
||||
self.definitions.set_invocation_parent(derive_invoc_id, parent_def);
|
||||
}
|
||||
self.invocations.extend(derives.iter().map(|&derive| (derive, invocation)));
|
||||
let mut visitor = BuildReducedGraphVisitor {
|
||||
resolver: self,
|
||||
current_legacy_scope: invocation.parent_legacy_scope,
|
||||
expansion: expn_id,
|
||||
r: self,
|
||||
parent_scope: ParentScope {
|
||||
module: invocation.module,
|
||||
expansion: expn_id,
|
||||
legacy: invocation.parent_legacy_scope,
|
||||
derives: Vec::new(),
|
||||
},
|
||||
};
|
||||
fragment.visit_with(&mut visitor);
|
||||
invocation.output_legacy_scope.set(Some(visitor.current_legacy_scope));
|
||||
invocation.output_legacy_scope.set(Some(visitor.parent_scope.legacy));
|
||||
}
|
||||
|
||||
fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension) {
|
||||
|
@ -191,7 +177,7 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||
}
|
||||
|
||||
fn resolve_imports(&mut self) {
|
||||
ImportResolver { resolver: self }.resolve_imports()
|
||||
ImportResolver { r: self }.resolve_imports()
|
||||
}
|
||||
|
||||
fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: ExpnId, force: bool)
|
||||
|
@ -210,10 +196,10 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||
// will automatically knows about itself.
|
||||
let mut result = Ok(None);
|
||||
if derives.len() > 1 {
|
||||
let parent_scope = self.invoc_parent_scope(invoc_id, Vec::new());
|
||||
let parent_scope = &self.invoc_parent_scope(invoc_id, Vec::new());
|
||||
for path in derives {
|
||||
match self.resolve_macro_path(path, Some(MacroKind::Derive),
|
||||
&parent_scope, true, force) {
|
||||
parent_scope, true, force) {
|
||||
Ok((Some(ref ext), _)) if ext.is_derive_copy => {
|
||||
self.add_derives(invoc.expansion_data.id, SpecialDerives::COPY);
|
||||
return Ok(None);
|
||||
|
@ -227,8 +213,8 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope);
|
||||
let (ext, res) = self.smart_resolve_macro_path(path, kind, &parent_scope, force)?;
|
||||
let parent_scope = &self.invoc_parent_scope(invoc_id, derives_in_scope);
|
||||
let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, force)?;
|
||||
|
||||
let span = invoc.span();
|
||||
invoc.expansion_data.id.set_expn_info(ext.expn_info(span, fast_print_path(path)));
|
||||
|
@ -388,8 +374,7 @@ impl<'a> Resolver<'a> {
|
|||
self.prohibit_imported_non_macro_attrs(None, res.ok(), path_span);
|
||||
res
|
||||
} else {
|
||||
// Macro without a specific kind restriction is equvalent to a macro import.
|
||||
let scope_set = kind.map_or(ScopeSet::Import(MacroNS), ScopeSet::Macro);
|
||||
let scope_set = kind.map_or(ScopeSet::All(MacroNS, false), ScopeSet::Macro);
|
||||
let binding = self.early_resolve_ident_in_lexical_scope(
|
||||
path[0].ident, scope_set, parent_scope, false, force, path_span
|
||||
);
|
||||
|
@ -444,10 +429,9 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
|
||||
let (ns, macro_kind, is_import) = match scope_set {
|
||||
ScopeSet::Import(ns) => (ns, None, true),
|
||||
ScopeSet::All(ns, is_import) => (ns, None, is_import),
|
||||
ScopeSet::AbsolutePath(ns) => (ns, None, false),
|
||||
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false),
|
||||
ScopeSet::Module => (TypeNS, None, false),
|
||||
};
|
||||
|
||||
// This is *the* result, resolution from the scope closest to the resolved identifier.
|
||||
|
@ -471,9 +455,9 @@ impl<'a> Resolver<'a> {
|
|||
Scope::DeriveHelpers => {
|
||||
let mut result = Err(Determinacy::Determined);
|
||||
for derive in &parent_scope.derives {
|
||||
let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
|
||||
let parent_scope = &ParentScope { derives: Vec::new(), ..*parent_scope };
|
||||
match this.resolve_macro_path(derive, Some(MacroKind::Derive),
|
||||
&parent_scope, true, force) {
|
||||
parent_scope, true, force) {
|
||||
Ok((Some(ext), _)) => if ext.helper_attrs.contains(&ident.name) {
|
||||
let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
|
||||
ty::Visibility::Public, derive.span, ExpnId::root())
|
||||
|
@ -502,7 +486,7 @@ impl<'a> Resolver<'a> {
|
|||
ModuleOrUniformRoot::Module(root_module),
|
||||
ident,
|
||||
ns,
|
||||
None,
|
||||
parent_scope,
|
||||
record_used,
|
||||
path_span,
|
||||
);
|
||||
|
@ -516,17 +500,16 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
}
|
||||
Scope::Module(module) => {
|
||||
let orig_current_module = mem::replace(&mut this.current_module, module);
|
||||
let adjusted_parent_scope = &ParentScope { module, ..parent_scope.clone() };
|
||||
let binding = this.resolve_ident_in_module_unadjusted_ext(
|
||||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
ns,
|
||||
None,
|
||||
adjusted_parent_scope,
|
||||
true,
|
||||
record_used,
|
||||
path_span,
|
||||
);
|
||||
this.current_module = orig_current_module;
|
||||
match binding {
|
||||
Ok(binding) => {
|
||||
let misc_flags = if ptr::eq(module, this.graph_root) {
|
||||
|
@ -588,6 +571,7 @@ impl<'a> Resolver<'a> {
|
|||
ModuleOrUniformRoot::Module(prelude),
|
||||
ident,
|
||||
ns,
|
||||
parent_scope,
|
||||
false,
|
||||
path_span,
|
||||
) {
|
||||
|
@ -710,9 +694,7 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn finalize_current_module_macro_resolutions(&mut self) {
|
||||
let module = self.current_module;
|
||||
|
||||
pub fn finalize_current_module_macro_resolutions(&mut self, module: Module<'a>) {
|
||||
let check_consistency = |this: &mut Self, path: &[Segment], span, kind: MacroKind,
|
||||
initial_res: Option<Res>, res: Res| {
|
||||
if let Some(initial_res) = initial_res {
|
||||
|
@ -753,8 +735,9 @@ impl<'a> Resolver<'a> {
|
|||
for (mut path, path_span, kind, parent_scope, initial_res) in macro_resolutions {
|
||||
// FIXME: Path resolution will ICE if segment IDs present.
|
||||
for seg in &mut path { seg.id = None; }
|
||||
match self.resolve_path(&path, Some(MacroNS), &parent_scope,
|
||||
true, path_span, CrateLint::No) {
|
||||
match self.resolve_path(
|
||||
&path, Some(MacroNS), &parent_scope, true, path_span, CrateLint::No
|
||||
) {
|
||||
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
|
||||
let res = path_res.base_res();
|
||||
check_consistency(self, &path, path_span, kind, initial_res, res);
|
||||
|
@ -766,7 +749,7 @@ impl<'a> Resolver<'a> {
|
|||
(path_span, format!("partially resolved path in {} {}",
|
||||
kind.article(), kind.descr()))
|
||||
};
|
||||
resolve_error(self, span, ResolutionError::FailedToResolve {
|
||||
self.report_error(span, ResolutionError::FailedToResolve {
|
||||
label,
|
||||
suggestion: None
|
||||
});
|
||||
|
@ -886,62 +869,4 @@ impl<'a> Resolver<'a> {
|
|||
|
||||
Lrc::new(result)
|
||||
}
|
||||
|
||||
pub fn define_macro(&mut self,
|
||||
item: &ast::Item,
|
||||
expansion: ExpnId,
|
||||
current_legacy_scope: &mut LegacyScope<'a>) {
|
||||
let (ext, ident, span, is_legacy) = match &item.node {
|
||||
ItemKind::MacroDef(def) => {
|
||||
let ext = self.compile_macro(item, self.session.edition());
|
||||
(ext, item.ident, item.span, def.legacy)
|
||||
}
|
||||
ItemKind::Fn(..) => match proc_macro_stub(item) {
|
||||
Some((macro_kind, ident, span)) => {
|
||||
self.proc_macro_stubs.insert(item.id);
|
||||
(self.dummy_ext(macro_kind), ident, span, false)
|
||||
}
|
||||
None => return,
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let def_id = self.definitions.local_def_id(item.id);
|
||||
let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id);
|
||||
self.macro_map.insert(def_id, ext);
|
||||
self.local_macro_def_scopes.insert(item.id, self.current_module);
|
||||
|
||||
if is_legacy {
|
||||
let ident = ident.modern();
|
||||
self.macro_names.insert(ident);
|
||||
let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export);
|
||||
let vis = if is_macro_export {
|
||||
ty::Visibility::Public
|
||||
} else {
|
||||
ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
|
||||
};
|
||||
let binding = (res, vis, span, expansion).to_name_binding(self.arenas);
|
||||
self.set_binding_parent_module(binding, self.current_module);
|
||||
let legacy_binding = self.arenas.alloc_legacy_binding(LegacyBinding {
|
||||
parent_legacy_scope: *current_legacy_scope, binding, ident
|
||||
});
|
||||
*current_legacy_scope = LegacyScope::Binding(legacy_binding);
|
||||
self.all_macros.insert(ident.name, res);
|
||||
if is_macro_export {
|
||||
let module = self.graph_root;
|
||||
self.define(module, ident, MacroNS,
|
||||
(res, vis, span, expansion, IsMacroExport));
|
||||
} else {
|
||||
self.check_reserved_macro_name(ident, res);
|
||||
self.unused_macros.insert(item.id, span);
|
||||
}
|
||||
} else {
|
||||
let module = self.current_module;
|
||||
let vis = self.resolve_visibility(&item.vis);
|
||||
if vis != ty::Visibility::Public {
|
||||
self.unused_macros.insert(item.id, span);
|
||||
}
|
||||
self.define(module, ident, MacroNS, (res, vis, span, expansion));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,8 @@ use crate::{CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, ParentScope
|
|||
use crate::Determinacy::{self, *};
|
||||
use crate::Namespace::{self, TypeNS, MacroNS};
|
||||
use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
|
||||
use crate::{Resolver, Segment};
|
||||
use crate::{Resolver, ResolutionError, Segment};
|
||||
use crate::{names_to_string, module_to_string};
|
||||
use crate::{resolve_error, ResolutionError};
|
||||
use crate::ModuleKind;
|
||||
use crate::diagnostics::Suggestion;
|
||||
|
||||
|
@ -27,7 +26,7 @@ use rustc::session::DiagnosticMessageId;
|
|||
use rustc::util::nodemap::FxHashSet;
|
||||
use rustc::{bug, span_bug};
|
||||
|
||||
use syntax::ast::{self, Ident, Name, NodeId, CRATE_NODE_ID};
|
||||
use syntax::ast::{Ident, Name, NodeId, CRATE_NODE_ID};
|
||||
use syntax::ext::hygiene::ExpnId;
|
||||
use syntax::symbol::kw;
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
|
@ -153,10 +152,14 @@ impl<'a> NameResolution<'a> {
|
|||
self.single_imports.is_empty() { Some(binding) } else { None }
|
||||
})
|
||||
}
|
||||
|
||||
crate fn add_single_import(&mut self, directive: &'a ImportDirective<'a>) {
|
||||
self.single_imports.insert(PtrKey(directive));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Resolver<'a> {
|
||||
fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
|
||||
crate fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
|
||||
-> &'a RefCell<NameResolution<'a>> {
|
||||
*module.resolutions.borrow_mut().entry((ident.modern(), ns))
|
||||
.or_insert_with(|| self.arenas.alloc_name_resolution())
|
||||
|
@ -167,11 +170,12 @@ impl<'a> Resolver<'a> {
|
|||
module: ModuleOrUniformRoot<'a>,
|
||||
ident: Ident,
|
||||
ns: Namespace,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
record_used: bool,
|
||||
path_span: Span,
|
||||
) -> Result<&'a NameBinding<'a>, Determinacy> {
|
||||
self.resolve_ident_in_module_unadjusted_ext(
|
||||
module, ident, ns, None, false, record_used, path_span
|
||||
module, ident, ns, parent_scope, false, record_used, path_span
|
||||
).map_err(|(determinacy, _)| determinacy)
|
||||
}
|
||||
|
||||
|
@ -182,7 +186,7 @@ impl<'a> Resolver<'a> {
|
|||
module: ModuleOrUniformRoot<'a>,
|
||||
ident: Ident,
|
||||
ns: Namespace,
|
||||
parent_scope: Option<&ParentScope<'a>>,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
restricted_shadowing: bool,
|
||||
record_used: bool,
|
||||
path_span: Span,
|
||||
|
@ -191,9 +195,8 @@ impl<'a> Resolver<'a> {
|
|||
ModuleOrUniformRoot::Module(module) => module,
|
||||
ModuleOrUniformRoot::CrateRootAndExternPrelude => {
|
||||
assert!(!restricted_shadowing);
|
||||
let parent_scope = self.dummy_parent_scope();
|
||||
let binding = self.early_resolve_ident_in_lexical_scope(
|
||||
ident, ScopeSet::AbsolutePath(ns), &parent_scope,
|
||||
ident, ScopeSet::AbsolutePath(ns), parent_scope,
|
||||
record_used, record_used, path_span,
|
||||
);
|
||||
return binding.map_err(|determinacy| (determinacy, Weak::No));
|
||||
|
@ -213,9 +216,6 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
ModuleOrUniformRoot::CurrentScope => {
|
||||
assert!(!restricted_shadowing);
|
||||
let parent_scope =
|
||||
parent_scope.expect("no parent scope for a single-segment import");
|
||||
|
||||
if ns == TypeNS {
|
||||
if ident.name == kw::Crate ||
|
||||
ident.name == kw::DollarCrate {
|
||||
|
@ -232,8 +232,9 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
let scopes = ScopeSet::All(ns, true);
|
||||
let binding = self.early_resolve_ident_in_lexical_scope(
|
||||
ident, ScopeSet::Import(ns), parent_scope, record_used, record_used, path_span
|
||||
ident, scopes, parent_scope, record_used, record_used, path_span
|
||||
);
|
||||
return binding.map_err(|determinacy| (determinacy, Weak::No));
|
||||
}
|
||||
|
@ -261,7 +262,8 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
// `extern crate` are always usable for backwards compatibility, see issue #37020,
|
||||
// remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`.
|
||||
let usable = this.is_accessible(binding.vis) || binding.is_extern_crate();
|
||||
let usable = this.is_accessible_from(binding.vis, parent_scope.module) ||
|
||||
binding.is_extern_crate();
|
||||
if usable { Ok(binding) } else { Err((Determined, Weak::No)) }
|
||||
};
|
||||
|
||||
|
@ -299,7 +301,7 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
if !self.is_accessible(binding.vis) &&
|
||||
if !self.is_accessible_from(binding.vis, parent_scope.module) &&
|
||||
// Remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`
|
||||
!(self.last_import_segment && binding.is_extern_crate()) {
|
||||
self.privacy_errors.push(PrivacyError(path_span, ident, binding));
|
||||
|
@ -322,7 +324,7 @@ impl<'a> Resolver<'a> {
|
|||
// Check if one of single imports can still define the name,
|
||||
// if it can then our result is not determined and can be invalidated.
|
||||
for single_import in &resolution.single_imports {
|
||||
if !self.is_accessible(single_import.vis.get()) {
|
||||
if !self.is_accessible_from(single_import.vis.get(), parent_scope.module) {
|
||||
continue;
|
||||
}
|
||||
let module = unwrap_or!(single_import.imported_module.get(),
|
||||
|
@ -331,7 +333,7 @@ impl<'a> Resolver<'a> {
|
|||
SingleImport { source, .. } => source,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
match self.resolve_ident_in_module(module, ident, ns, Some(&single_import.parent_scope),
|
||||
match self.resolve_ident_in_module(module, ident, ns, &single_import.parent_scope,
|
||||
false, path_span) {
|
||||
Err(Determined) => continue,
|
||||
Ok(binding) if !self.is_accessible_from(
|
||||
|
@ -379,7 +381,7 @@ impl<'a> Resolver<'a> {
|
|||
// Check if one of glob imports can still define the name,
|
||||
// if it can then our "no resolution" result is not determined and can be invalidated.
|
||||
for glob_import in module.globs.borrow().iter() {
|
||||
if !self.is_accessible(glob_import.vis.get()) {
|
||||
if !self.is_accessible_from(glob_import.vis.get(), parent_scope.module) {
|
||||
continue
|
||||
}
|
||||
let module = match glob_import.imported_module.get() {
|
||||
|
@ -387,9 +389,14 @@ impl<'a> Resolver<'a> {
|
|||
Some(_) => continue,
|
||||
None => return Err((Undetermined, Weak::Yes)),
|
||||
};
|
||||
let (orig_current_module, mut ident) = (self.current_module, ident.modern());
|
||||
let tmp_parent_scope;
|
||||
let (mut adjusted_parent_scope, mut ident) = (parent_scope, ident.modern());
|
||||
match ident.span.glob_adjust(module.expansion, glob_import.span) {
|
||||
Some(Some(def)) => self.current_module = self.macro_def_scope(def),
|
||||
Some(Some(def)) => {
|
||||
tmp_parent_scope =
|
||||
ParentScope { module: self.macro_def_scope(def), ..parent_scope.clone() };
|
||||
adjusted_parent_scope = &tmp_parent_scope;
|
||||
}
|
||||
Some(None) => {}
|
||||
None => continue,
|
||||
};
|
||||
|
@ -397,10 +404,10 @@ impl<'a> Resolver<'a> {
|
|||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
ns,
|
||||
adjusted_parent_scope,
|
||||
false,
|
||||
path_span,
|
||||
);
|
||||
self.current_module = orig_current_module;
|
||||
|
||||
match result {
|
||||
Err(Determined) => continue,
|
||||
|
@ -415,52 +422,6 @@ impl<'a> Resolver<'a> {
|
|||
Err((Determined, Weak::No))
|
||||
}
|
||||
|
||||
// Add an import directive to the current module.
|
||||
pub fn add_import_directive(&mut self,
|
||||
module_path: Vec<Segment>,
|
||||
subclass: ImportDirectiveSubclass<'a>,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
item: &ast::Item,
|
||||
root_span: Span,
|
||||
root_id: NodeId,
|
||||
vis: ty::Visibility,
|
||||
parent_scope: ParentScope<'a>) {
|
||||
let current_module = parent_scope.module;
|
||||
let directive = self.arenas.alloc_import_directive(ImportDirective {
|
||||
parent_scope,
|
||||
module_path,
|
||||
imported_module: Cell::new(None),
|
||||
subclass,
|
||||
span,
|
||||
id,
|
||||
use_span: item.span,
|
||||
use_span_with_attributes: item.span_with_attributes(),
|
||||
has_attributes: !item.attrs.is_empty(),
|
||||
root_span,
|
||||
root_id,
|
||||
vis: Cell::new(vis),
|
||||
used: Cell::new(false),
|
||||
});
|
||||
|
||||
debug!("add_import_directive({:?})", directive);
|
||||
|
||||
self.indeterminate_imports.push(directive);
|
||||
match directive.subclass {
|
||||
SingleImport { target, type_ns_only, .. } => {
|
||||
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
|
||||
let mut resolution = this.resolution(current_module, target, ns).borrow_mut();
|
||||
resolution.single_imports.insert(PtrKey(directive));
|
||||
});
|
||||
}
|
||||
// We don't add prelude imports to the globs since they only affect lexical scopes,
|
||||
// which are not relevant to import resolution.
|
||||
GlobImport { is_prelude: true, .. } => {}
|
||||
GlobImport { .. } => current_module.globs.borrow_mut().push(directive),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
// Given a binding and an import directive that resolves to it,
|
||||
// return the corresponding binding defined by the import directive.
|
||||
crate fn import(&self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
|
||||
|
@ -635,25 +596,12 @@ struct UnresolvedImportError {
|
|||
}
|
||||
|
||||
pub struct ImportResolver<'a, 'b> {
|
||||
pub resolver: &'a mut Resolver<'b>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> std::ops::Deref for ImportResolver<'a, 'b> {
|
||||
type Target = Resolver<'b>;
|
||||
fn deref(&self) -> &Resolver<'b> {
|
||||
self.resolver
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> std::ops::DerefMut for ImportResolver<'a, 'b> {
|
||||
fn deref_mut(&mut self) -> &mut Resolver<'b> {
|
||||
self.resolver
|
||||
}
|
||||
pub r: &'a mut Resolver<'b>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> ty::DefIdTree for &'a ImportResolver<'a, 'b> {
|
||||
fn parent(self, id: DefId) -> Option<DefId> {
|
||||
self.resolver.parent(id)
|
||||
self.r.parent(id)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -669,20 +617,20 @@ 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.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) {
|
||||
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) {
|
||||
match self.resolve_import(&import) {
|
||||
true => self.determined_imports.push(import),
|
||||
false => self.indeterminate_imports.push(import),
|
||||
true => self.r.determined_imports.push(import),
|
||||
false => self.r.indeterminate_imports.push(import),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finalize_imports(&mut self) {
|
||||
for module in self.arenas.local_modules().iter() {
|
||||
for module in self.r.arenas.local_modules().iter() {
|
||||
self.finalize_resolutions_in(module);
|
||||
}
|
||||
|
||||
|
@ -690,8 +638,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
let mut seen_spans = FxHashSet::default();
|
||||
let mut errors = vec![];
|
||||
let mut prev_root_id: NodeId = NodeId::from_u32(0);
|
||||
for i in 0 .. self.determined_imports.len() {
|
||||
let import = self.determined_imports[i];
|
||||
for i in 0 .. self.r.determined_imports.len() {
|
||||
let import = self.r.determined_imports[i];
|
||||
if let Some(err) = self.finalize_import(import) {
|
||||
has_errors = true;
|
||||
|
||||
|
@ -706,7 +654,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
|
||||
// If the error is a single failed import then create a "fake" import
|
||||
// resolution for it so that later resolve stages won't complain.
|
||||
self.import_dummy_binding(import);
|
||||
self.r.import_dummy_binding(import);
|
||||
if prev_root_id.as_u32() != 0
|
||||
&& prev_root_id.as_u32() != import.root_id.as_u32()
|
||||
&& !errors.is_empty() {
|
||||
|
@ -735,7 +683,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
// Report unresolved imports only if no hard error was already reported
|
||||
// to avoid generating multiple errors on the same import.
|
||||
if !has_errors {
|
||||
for import in &self.indeterminate_imports {
|
||||
for import in &self.r.indeterminate_imports {
|
||||
self.throw_unresolved_import_error(errors, Some(MultiSpan::from(import.span)));
|
||||
break;
|
||||
}
|
||||
|
@ -774,7 +722,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
(span, msg)
|
||||
};
|
||||
|
||||
let mut diag = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg);
|
||||
let mut diag = struct_span_err!(self.r.session, span, E0432, "{}", &msg);
|
||||
|
||||
if let Some((_, UnresolvedImportError { note, .. })) = errors.iter().last() {
|
||||
for message in note {
|
||||
|
@ -798,11 +746,11 @@ 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, directive: &'b ImportDirective<'b>) -> bool {
|
||||
debug!("(resolving import for module) resolving import `{}::...` in `{}`",
|
||||
Segment::names_to_string(&directive.module_path),
|
||||
module_to_string(self.current_module).unwrap_or_else(|| "???".to_string()));
|
||||
|
||||
self.current_module = directive.parent_scope.module;
|
||||
debug!(
|
||||
"(resolving import for module) resolving import `{}::...` in `{}`",
|
||||
Segment::names_to_string(&directive.module_path),
|
||||
module_to_string(directive.parent_scope.module).unwrap_or_else(|| "???".to_string()),
|
||||
);
|
||||
|
||||
let module = if let Some(module) = directive.imported_module.get() {
|
||||
module
|
||||
|
@ -810,7 +758,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 = directive.vis.replace(ty::Visibility::Invisible);
|
||||
let path_res = self.resolve_path(
|
||||
let path_res = self.r.resolve_path(
|
||||
&directive.module_path,
|
||||
None,
|
||||
&directive.parent_scope,
|
||||
|
@ -841,13 +789,13 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
};
|
||||
|
||||
let mut indeterminate = false;
|
||||
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
|
||||
self.r.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
|
||||
// not define any names while resolving its module path.
|
||||
let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
|
||||
let binding = this.resolve_ident_in_module(
|
||||
module, source, ns, Some(&directive.parent_scope), false, directive.span
|
||||
module, source, ns, &directive.parent_scope, false, directive.span
|
||||
);
|
||||
directive.vis.set(orig_vis);
|
||||
|
||||
|
@ -892,13 +840,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
&mut self,
|
||||
directive: &'b ImportDirective<'b>
|
||||
) -> Option<UnresolvedImportError> {
|
||||
self.current_module = directive.parent_scope.module;
|
||||
|
||||
let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
|
||||
let prev_ambiguity_errors_len = self.ambiguity_errors.len();
|
||||
let path_res = self.resolve_path(&directive.module_path, None, &directive.parent_scope,
|
||||
let prev_ambiguity_errors_len = self.r.ambiguity_errors.len();
|
||||
let path_res = self.r.resolve_path(&directive.module_path, None, &directive.parent_scope,
|
||||
true, directive.span, directive.crate_lint());
|
||||
let no_ambiguity = self.ambiguity_errors.len() == prev_ambiguity_errors_len;
|
||||
let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
|
||||
directive.vis.set(orig_vis);
|
||||
let module = match path_res {
|
||||
PathResult::Module(module) => {
|
||||
|
@ -908,10 +854,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
span_bug!(directive.span, "inconsistent resolution for an import");
|
||||
}
|
||||
} else {
|
||||
if self.privacy_errors.is_empty() {
|
||||
if self.r.privacy_errors.is_empty() {
|
||||
let msg = "cannot determine resolution for the import";
|
||||
let msg_note = "import resolution is stuck, try simplifying other imports";
|
||||
self.session.struct_span_err(directive.span, msg).note(msg_note).emit();
|
||||
self.r.session.struct_span_err(directive.span, msg).note(msg_note).emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -920,7 +866,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
|
||||
if no_ambiguity {
|
||||
assert!(directive.imported_module.get().is_none());
|
||||
resolve_error(self, span, ResolutionError::FailedToResolve {
|
||||
self.r.report_error(span, ResolutionError::FailedToResolve {
|
||||
label,
|
||||
suggestion,
|
||||
});
|
||||
|
@ -982,7 +928,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
// 2 segments, so the `resolve_path` above won't trigger it.
|
||||
let mut full_path = directive.module_path.clone();
|
||||
full_path.push(Segment::from_ident(Ident::invalid()));
|
||||
self.lint_if_path_starts_with_module(
|
||||
self.r.lint_if_path_starts_with_module(
|
||||
directive.crate_lint(),
|
||||
&full_path,
|
||||
directive.span,
|
||||
|
@ -1005,7 +951,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
max_vis.get() != ty::Visibility::Invisible && // Allow empty globs.
|
||||
!max_vis.get().is_at_least(directive.vis.get(), &*self) {
|
||||
let msg = "A non-empty glob must import something with the glob's visibility";
|
||||
self.session.span_err(directive.span, msg);
|
||||
self.r.session.span_err(directive.span, msg);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
@ -1013,13 +959,13 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
};
|
||||
|
||||
let mut all_ns_err = true;
|
||||
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
|
||||
self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
|
||||
let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
|
||||
let orig_blacklisted_binding =
|
||||
mem::replace(&mut this.blacklisted_binding, target_bindings[ns].get());
|
||||
let orig_last_import_segment = mem::replace(&mut this.last_import_segment, true);
|
||||
let binding = this.resolve_ident_in_module(
|
||||
module, ident, ns, Some(&directive.parent_scope), true, directive.span
|
||||
module, ident, ns, &directive.parent_scope, true, directive.span
|
||||
);
|
||||
this.last_import_segment = orig_last_import_segment;
|
||||
this.blacklisted_binding = orig_blacklisted_binding;
|
||||
|
@ -1068,9 +1014,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
|
||||
if all_ns_err {
|
||||
let mut all_ns_failed = true;
|
||||
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
|
||||
self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
|
||||
let binding = this.resolve_ident_in_module(
|
||||
module, ident, ns, Some(&directive.parent_scope), true, directive.span
|
||||
module, ident, ns, &directive.parent_scope, true, directive.span
|
||||
);
|
||||
if binding.is_ok() {
|
||||
all_ns_failed = false;
|
||||
|
@ -1147,14 +1093,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
})
|
||||
} else {
|
||||
// `resolve_ident_in_module` reported a privacy error.
|
||||
self.import_dummy_binding(directive);
|
||||
self.r.import_dummy_binding(directive);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
let mut reexport_error = None;
|
||||
let mut any_successful_reexport = false;
|
||||
self.per_ns(|this, ns| {
|
||||
self.r.per_ns(|this, ns| {
|
||||
if let Ok(binding) = source_bindings[ns].get() {
|
||||
let vis = directive.vis.get();
|
||||
if !binding.pseudo_vis().is_at_least(vis, &*this) {
|
||||
|
@ -1173,12 +1119,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
re-exported (error E0365), consider declaring with \
|
||||
`pub`",
|
||||
ident);
|
||||
self.session.buffer_lint(PUB_USE_OF_PRIVATE_EXTERN_CRATE,
|
||||
self.r.session.buffer_lint(PUB_USE_OF_PRIVATE_EXTERN_CRATE,
|
||||
directive.id,
|
||||
directive.span,
|
||||
&msg);
|
||||
} else if ns == TypeNS {
|
||||
struct_span_err!(self.session, directive.span, E0365,
|
||||
struct_span_err!(self.r.session, directive.span, E0365,
|
||||
"`{}` is private, and cannot be re-exported", ident)
|
||||
.span_label(directive.span, format!("re-export of private `{}`", ident))
|
||||
.note(&format!("consider declaring type or module `{}` with `pub`", ident))
|
||||
|
@ -1187,7 +1133,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
let msg = format!("`{}` is private, and cannot be re-exported", ident);
|
||||
let note_msg =
|
||||
format!("consider marking `{}` as `pub` in the imported module", ident);
|
||||
struct_span_err!(self.session, directive.span, E0364, "{}", &msg)
|
||||
struct_span_err!(self.r.session, directive.span, E0364, "{}", &msg)
|
||||
.span_note(directive.span, ¬e_msg)
|
||||
.emit();
|
||||
}
|
||||
|
@ -1198,7 +1144,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
// 2 segments, so the `resolve_path` above won't trigger it.
|
||||
let mut full_path = directive.module_path.clone();
|
||||
full_path.push(Segment::from_ident(ident));
|
||||
self.per_ns(|this, ns| {
|
||||
self.r.per_ns(|this, ns| {
|
||||
if let Ok(binding) = source_bindings[ns].get() {
|
||||
this.lint_if_path_starts_with_module(
|
||||
directive.crate_lint(),
|
||||
|
@ -1213,7 +1159,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.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() {
|
||||
self.r.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() {
|
||||
this.import_res_map.entry(directive.id).or_default()[ns] = Some(binding.res());
|
||||
});
|
||||
|
||||
|
@ -1260,7 +1206,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
macro_ns: None,
|
||||
};
|
||||
|
||||
self.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() {
|
||||
self.r.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() {
|
||||
if binding.res() == Res::Err {
|
||||
return;
|
||||
}
|
||||
|
@ -1272,7 +1218,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
|
||||
match this.early_resolve_ident_in_lexical_scope(
|
||||
target,
|
||||
ScopeSet::Import(ns),
|
||||
ScopeSet::All(ns, false),
|
||||
&directive.parent_scope,
|
||||
false,
|
||||
false,
|
||||
|
@ -1298,7 +1244,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
let mut redundant_spans: Vec<_> = redundant_span.present_items().collect();
|
||||
redundant_spans.sort();
|
||||
redundant_spans.dedup();
|
||||
self.session.buffer_lint_with_diagnostic(
|
||||
self.r.session.buffer_lint_with_diagnostic(
|
||||
UNUSED_IMPORTS,
|
||||
directive.id,
|
||||
directive.span,
|
||||
|
@ -1312,20 +1258,20 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
let module = match directive.imported_module.get().unwrap() {
|
||||
ModuleOrUniformRoot::Module(module) => module,
|
||||
_ => {
|
||||
self.session.span_err(directive.span, "cannot glob-import all possible crates");
|
||||
self.r.session.span_err(directive.span, "cannot glob-import all possible crates");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
self.populate_module_if_necessary(module);
|
||||
self.r.populate_module_if_necessary(module);
|
||||
|
||||
if module.is_trait() {
|
||||
self.session.span_err(directive.span, "items in traits are not importable.");
|
||||
self.r.session.span_err(directive.span, "items in traits are not importable.");
|
||||
return;
|
||||
} else if module.def_id() == directive.parent_scope.module.def_id() {
|
||||
return;
|
||||
} else if let GlobImport { is_prelude: true, .. } = directive.subclass {
|
||||
self.prelude = Some(module);
|
||||
self.r.prelude = Some(module);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1339,18 +1285,19 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
}).collect::<Vec<_>>();
|
||||
for ((mut ident, ns), binding) in bindings {
|
||||
let scope = match ident.span.reverse_glob_adjust(module.expansion, directive.span) {
|
||||
Some(Some(def)) => self.macro_def_scope(def),
|
||||
Some(None) => self.current_module,
|
||||
Some(Some(def)) => self.r.macro_def_scope(def),
|
||||
Some(None) => directive.parent_scope.module,
|
||||
None => continue,
|
||||
};
|
||||
if self.is_accessible_from(binding.pseudo_vis(), scope) {
|
||||
let imported_binding = self.import(binding, directive);
|
||||
let _ = self.try_define(directive.parent_scope.module, ident, ns, imported_binding);
|
||||
if self.r.is_accessible_from(binding.pseudo_vis(), scope) {
|
||||
let imported_binding = self.r.import(binding, directive);
|
||||
let _ =
|
||||
self.r.try_define(directive.parent_scope.module, ident, ns, imported_binding);
|
||||
}
|
||||
}
|
||||
|
||||
// Record the destination of this import
|
||||
self.record_partial_res(directive.id, PartialRes::new(module.res().unwrap()));
|
||||
self.r.record_partial_res(directive.id, PartialRes::new(module.res().unwrap()));
|
||||
}
|
||||
|
||||
// Miscellaneous post-processing, including recording re-exports,
|
||||
|
@ -1379,7 +1326,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
if res != Res::Err {
|
||||
if let Some(def_id) = res.opt_def_id() {
|
||||
if !def_id.is_local() {
|
||||
self.cstore.export_macros_untracked(def_id.krate);
|
||||
self.r.cstore.export_macros_untracked(def_id.krate);
|
||||
}
|
||||
}
|
||||
reexports.push(Export {
|
||||
|
@ -1405,7 +1352,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
let error_id = (DiagnosticMessageId::ErrorId(0), // no code?!
|
||||
Some(binding.span),
|
||||
msg.clone());
|
||||
let fresh = self.session.one_time_diagnostics
|
||||
let fresh = self.r.session.one_time_diagnostics
|
||||
.borrow_mut().insert(error_id);
|
||||
if !fresh {
|
||||
continue;
|
||||
|
@ -1414,7 +1361,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
},
|
||||
ref s @ _ => bug!("unexpected import subclass {:?}", s)
|
||||
};
|
||||
let mut err = self.session.struct_span_err(binding.span, &msg);
|
||||
let mut err = self.r.session.struct_span_err(binding.span, &msg);
|
||||
|
||||
let imported_module = match directive.imported_module.get() {
|
||||
Some(ModuleOrUniformRoot::Module(module)) => module,
|
||||
|
@ -1430,8 +1377,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
let enum_span = enum_resolution.borrow()
|
||||
.binding.expect("binding should exist")
|
||||
.span;
|
||||
let enum_def_span = self.session.source_map().def_span(enum_span);
|
||||
let enum_def_snippet = self.session.source_map()
|
||||
let enum_def_span = self.r.session.source_map().def_span(enum_span);
|
||||
let enum_def_snippet = self.r.session.source_map()
|
||||
.span_to_snippet(enum_def_span).expect("snippet should exist");
|
||||
// potentially need to strip extant `crate`/`pub(path)` for suggestion
|
||||
let after_vis_index = enum_def_snippet.find("enum")
|
||||
|
@ -1439,7 +1386,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
let suggestion = format!("pub {}",
|
||||
&enum_def_snippet[after_vis_index..]);
|
||||
|
||||
self.session
|
||||
self.r.session
|
||||
.diag_span_suggestion_once(&mut err,
|
||||
DiagnosticMessageId::ErrorId(0),
|
||||
enum_def_span,
|
||||
|
@ -1452,7 +1399,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
|
||||
if reexports.len() > 0 {
|
||||
if let Some(def_id) = module.def_id() {
|
||||
self.export_map.insert(def_id, reexports);
|
||||
self.r.export_map.insert(def_id, reexports);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,15 +61,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||
{
|
||||
let cx = self.cx;
|
||||
|
||||
// In case we're in a module, try to resolve the relative
|
||||
// path.
|
||||
if let Some(id) = parent_id.or(self.mod_ids.last().cloned()) {
|
||||
// FIXME: `with_scope` requires the `NodeId` of a module.
|
||||
let node_id = cx.tcx.hir().hir_to_node_id(id);
|
||||
// In case we're in a module, try to resolve the relative path.
|
||||
if let Some(module_id) = parent_id.or(self.mod_ids.last().cloned()) {
|
||||
let module_id = cx.tcx.hir().hir_to_node_id(module_id);
|
||||
let result = cx.enter_resolver(|resolver| {
|
||||
resolver.with_scope(node_id, |resolver| {
|
||||
resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns == ValueNS)
|
||||
})
|
||||
resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
|
||||
});
|
||||
let result = match result {
|
||||
Ok((_, Res::Err)) => Err(()),
|
||||
|
@ -85,6 +81,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||
Res::Def(DefKind::AssocTy, _) => false,
|
||||
Res::Def(DefKind::Variant, _) => return handle_variant(cx, res),
|
||||
// Not a trait item; just return what we found.
|
||||
Res::PrimTy(..) => return Ok((res, Some(path_str.to_owned()))),
|
||||
_ => return Ok((res, None))
|
||||
};
|
||||
|
||||
|
@ -133,11 +130,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||
.ok_or(());
|
||||
}
|
||||
|
||||
// FIXME: `with_scope` requires the `NodeId` of a module.
|
||||
let node_id = cx.tcx.hir().hir_to_node_id(id);
|
||||
let (_, ty_res) = cx.enter_resolver(|resolver| resolver.with_scope(node_id, |resolver| {
|
||||
resolver.resolve_str_path_error(DUMMY_SP, &path, false)
|
||||
}))?;
|
||||
let (_, ty_res) = cx.enter_resolver(|resolver| {
|
||||
resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
|
||||
})?;
|
||||
if let Res::Err = ty_res {
|
||||
return Err(());
|
||||
}
|
||||
|
|
17
src/test/ui/hygiene/privacy-early.rs
Normal file
17
src/test/ui/hygiene/privacy-early.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
// edition:2018
|
||||
|
||||
#![feature(decl_macro)]
|
||||
|
||||
mod foo {
|
||||
fn f() {}
|
||||
macro f() {}
|
||||
|
||||
pub macro m() {
|
||||
use f as g; //~ ERROR `f` is private, and cannot be re-exported
|
||||
f!();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo::m!();
|
||||
}
|
21
src/test/ui/hygiene/privacy-early.stderr
Normal file
21
src/test/ui/hygiene/privacy-early.stderr
Normal file
|
@ -0,0 +1,21 @@
|
|||
error[E0364]: `f` is private, and cannot be re-exported
|
||||
--> $DIR/privacy-early.rs:10:13
|
||||
|
|
||||
LL | use f as g;
|
||||
| ^^^^^^
|
||||
...
|
||||
LL | foo::m!();
|
||||
| ---------- in this macro invocation
|
||||
|
|
||||
note: consider marking `f` as `pub` in the imported module
|
||||
--> $DIR/privacy-early.rs:10:13
|
||||
|
|
||||
LL | use f as g;
|
||||
| ^^^^^^
|
||||
...
|
||||
LL | foo::m!();
|
||||
| ---------- in this macro invocation
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0364`.
|
|
@ -1,5 +1,5 @@
|
|||
// edition:2018
|
||||
// build-pass (FIXME(62277): could be check-pass?)
|
||||
// check-pass
|
||||
// revisions: migrate mir
|
||||
//[mir]compile-flags: -Z borrowck=mir
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@ trait Tr {}
|
|||
pub(in E) struct S; //~ ERROR expected module, found enum `E`
|
||||
pub(in Tr) struct Z; //~ ERROR expected module, found trait `Tr`
|
||||
pub(in std::vec) struct F; //~ ERROR visibilities can only be restricted to ancestor modules
|
||||
pub(in nonexistent) struct G; //~ ERROR cannot find module `nonexistent` in the crate root
|
||||
pub(in too_soon) struct H; //~ ERROR cannot find module `too_soon` in the crate root
|
||||
pub(in nonexistent) struct G; //~ ERROR failed to resolve
|
||||
pub(in too_soon) struct H; //~ ERROR failed to resolve
|
||||
|
||||
// Visibilities are resolved eagerly without waiting for modules becoming fully populated.
|
||||
// Visibilities can only use ancestor modules legally which are always available in time,
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
error: visibilities can only be restricted to ancestor modules
|
||||
--> $DIR/resolve-bad-visibility.rs:6:8
|
||||
|
|
||||
LL | pub(in std::vec) struct F;
|
||||
| ^^^^^^^^
|
||||
|
||||
error[E0577]: expected module, found enum `E`
|
||||
--> $DIR/resolve-bad-visibility.rs:4:8
|
||||
|
|
||||
|
@ -16,17 +10,24 @@ error[E0577]: expected module, found trait `Tr`
|
|||
LL | pub(in Tr) struct Z;
|
||||
| ^^ not a module
|
||||
|
||||
error[E0578]: cannot find module `nonexistent` in the crate root
|
||||
error: visibilities can only be restricted to ancestor modules
|
||||
--> $DIR/resolve-bad-visibility.rs:6:8
|
||||
|
|
||||
LL | pub(in std::vec) struct F;
|
||||
| ^^^^^^^^
|
||||
|
||||
error[E0433]: failed to resolve: maybe a missing crate `nonexistent`?
|
||||
--> $DIR/resolve-bad-visibility.rs:7:8
|
||||
|
|
||||
LL | pub(in nonexistent) struct G;
|
||||
| ^^^^^^^^^^^ not found in the crate root
|
||||
| ^^^^^^^^^^^ maybe a missing crate `nonexistent`?
|
||||
|
||||
error[E0578]: cannot find module `too_soon` in the crate root
|
||||
error[E0433]: failed to resolve: maybe a missing crate `too_soon`?
|
||||
--> $DIR/resolve-bad-visibility.rs:8:8
|
||||
|
|
||||
LL | pub(in too_soon) struct H;
|
||||
| ^^^^^^^^ not found in the crate root
|
||||
| ^^^^^^^^ maybe a missing crate `too_soon`?
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
||||
|
|
5
src/test/ui/resolve/visibility-indeterminate.rs
Normal file
5
src/test/ui/resolve/visibility-indeterminate.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
// edition:2018
|
||||
|
||||
foo!(); //~ ERROR cannot find macro `foo!` in this scope
|
||||
|
||||
pub(in ::bar) struct Baz {} //~ ERROR cannot determine resolution for the visibility
|
19
src/test/ui/resolve/visibility-indeterminate.stderr
Normal file
19
src/test/ui/resolve/visibility-indeterminate.stderr
Normal file
|
@ -0,0 +1,19 @@
|
|||
error[E0578]: cannot determine resolution for the visibility
|
||||
--> $DIR/visibility-indeterminate.rs:5:8
|
||||
|
|
||||
LL | pub(in ::bar) struct Baz {}
|
||||
| ^^^^^
|
||||
|
||||
error: cannot find macro `foo!` in this scope
|
||||
--> $DIR/visibility-indeterminate.rs:3:1
|
||||
|
|
||||
LL | foo!();
|
||||
| ^^^
|
||||
|
||||
error[E0601]: `main` function not found in crate `visibility_indeterminate`
|
||||
|
|
||||
= note: consider adding a `main` function to `$DIR/visibility-indeterminate.rs`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0601`.
|
|
@ -4,19 +4,17 @@ error: unexpected generic arguments in path
|
|||
LL | m!{ S<u8> }
|
||||
| ^^^^^
|
||||
|
||||
error[E0577]: expected module, found struct `S`
|
||||
--> $DIR/visibility-ty-params.rs:6:5
|
||||
|
|
||||
LL | m!{ S<u8> }
|
||||
| ^^^^^ not a module
|
||||
|
||||
error: unexpected generic arguments in path
|
||||
--> $DIR/visibility-ty-params.rs:10:9
|
||||
|
|
||||
LL | m!{ m<> }
|
||||
| ^^^
|
||||
|
||||
error[E0577]: expected module, found struct `S`
|
||||
--> $DIR/visibility-ty-params.rs:6:5
|
||||
|
|
||||
LL | m!{ S<u8> }
|
||||
| -^^^^
|
||||
| |
|
||||
| help: a module with a similar name exists: `m`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue