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:
bors 2019-08-10 13:44:09 +00:00
commit be3fb0cd2c
20 changed files with 4498 additions and 4415 deletions

3
.gitignore vendored
View file

@ -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

View file

@ -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(

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff

View 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

View file

@ -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));
}
}
}

View file

@ -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, &note_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);
}
}
}

View file

@ -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(());
}

View 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!();
}

View 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`.

View file

@ -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

View file

@ -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,

View file

@ -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`.

View 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

View 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`.

View file

@ -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