mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-17 05:25:37 +03:00
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:
@@ -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::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 @@ fn resolve_str_path(
|
||||
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 @@ fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
|
||||
})
|
||||
}
|
||||
|
||||
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 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
|
||||
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 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
|
||||
));
|
||||
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 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
|
||||
);
|
||||
|
||||
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 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
|
||||
));
|
||||
|
||||
// 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 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
|
||||
}
|
||||
|
||||
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 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
|
||||
})
|
||||
.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 @@ fn stmt(&mut self, span: Span, node: hir::StmtKind) -> hir::Stmt {
|
||||
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 @@ fn std_path(
|
||||
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 @@ fn lower_await(
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
//! Here we build the "reduced graph": the graph of the module tree without
|
||||
//! any imports resolved.
|
||||
|
||||
use crate::macros::{InvocationData, LegacyScope};
|
||||
use crate::macros::{InvocationData, LegacyBinding, LegacyScope};
|
||||
use crate::resolve_imports::ImportDirective;
|
||||
use crate::resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport};
|
||||
use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding};
|
||||
use crate::{ModuleOrUniformRoot, ParentScope, PerNS, Resolver, ResolverArenas, ExternPreludeEntry};
|
||||
use crate::Namespace::{self, TypeNS, ValueNS, MacroNS};
|
||||
use crate::{resolve_error, resolve_struct_error, ResolutionError, Determinacy};
|
||||
use crate::{ResolutionError, Determinacy, PathResult, CrateLint};
|
||||
|
||||
use rustc::bug;
|
||||
use rustc::hir::def::{self, *};
|
||||
@@ -29,11 +29,11 @@
|
||||
|
||||
use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId};
|
||||
use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind, Variant};
|
||||
use syntax::ext::base::SyntaxExtension;
|
||||
use syntax::ext::base::{MacroKind, SyntaxExtension};
|
||||
use syntax::ext::hygiene::ExpnId;
|
||||
use syntax::feature_gate::is_builtin_attr;
|
||||
use syntax::parse::token::{self, Token};
|
||||
use syntax::span_err;
|
||||
use syntax::{span_err, struct_span_err};
|
||||
use syntax::symbol::{kw, sym};
|
||||
use syntax::visit::{self, Visitor};
|
||||
|
||||
@@ -93,628 +93,6 @@ pub fn define<T>(&mut self, parent: Module<'a>, ident: Ident, ns: Namespace, def
|
||||
}
|
||||
}
|
||||
|
||||
fn block_needs_anonymous_module(&mut self, block: &Block) -> bool {
|
||||
// If any statements are items, we need to create an anonymous module
|
||||
block.stmts.iter().any(|statement| match statement.node {
|
||||
StmtKind::Item(_) | StmtKind::Mac(_) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
fn insert_field_names(&mut self, def_id: DefId, field_names: Vec<Name>) {
|
||||
if !field_names.is_empty() {
|
||||
self.field_names.insert(def_id, field_names);
|
||||
}
|
||||
}
|
||||
|
||||
fn build_reduced_graph_for_use_tree(
|
||||
&mut self,
|
||||
// This particular use tree
|
||||
use_tree: &ast::UseTree,
|
||||
id: NodeId,
|
||||
parent_prefix: &[Segment],
|
||||
nested: bool,
|
||||
// The whole `use` item
|
||||
parent_scope: ParentScope<'a>,
|
||||
item: &Item,
|
||||
vis: ty::Visibility,
|
||||
root_span: Span,
|
||||
) {
|
||||
debug!("build_reduced_graph_for_use_tree(parent_prefix={:?}, use_tree={:?}, nested={})",
|
||||
parent_prefix, use_tree, nested);
|
||||
|
||||
let mut prefix_iter = parent_prefix.iter().cloned()
|
||||
.chain(use_tree.prefix.segments.iter().map(|seg| seg.into())).peekable();
|
||||
|
||||
// On 2015 edition imports are resolved as crate-relative by default,
|
||||
// so prefixes are prepended with crate root segment if necessary.
|
||||
// The root is prepended lazily, when the first non-empty prefix or terminating glob
|
||||
// appears, so imports in braced groups can have roots prepended independently.
|
||||
let is_glob = if let ast::UseTreeKind::Glob = use_tree.kind { true } else { false };
|
||||
let crate_root = match prefix_iter.peek() {
|
||||
Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.rust_2015() => {
|
||||
Some(seg.ident.span.ctxt())
|
||||
}
|
||||
None if is_glob && use_tree.span.rust_2015() => {
|
||||
Some(use_tree.span.ctxt())
|
||||
}
|
||||
_ => None,
|
||||
}.map(|ctxt| Segment::from_ident(Ident::new(
|
||||
kw::PathRoot, use_tree.prefix.span.shrink_to_lo().with_ctxt(ctxt)
|
||||
)));
|
||||
|
||||
let prefix = crate_root.into_iter().chain(prefix_iter).collect::<Vec<_>>();
|
||||
debug!("build_reduced_graph_for_use_tree: prefix={:?}", prefix);
|
||||
|
||||
let empty_for_self = |prefix: &[Segment]| {
|
||||
prefix.is_empty() ||
|
||||
prefix.len() == 1 && prefix[0].ident.name == kw::PathRoot
|
||||
};
|
||||
match use_tree.kind {
|
||||
ast::UseTreeKind::Simple(rename, ..) => {
|
||||
let mut ident = use_tree.ident().gensym_if_underscore();
|
||||
let mut module_path = prefix;
|
||||
let mut source = module_path.pop().unwrap();
|
||||
let mut type_ns_only = false;
|
||||
|
||||
if nested {
|
||||
// Correctly handle `self`
|
||||
if source.ident.name == kw::SelfLower {
|
||||
type_ns_only = true;
|
||||
|
||||
if empty_for_self(&module_path) {
|
||||
resolve_error(
|
||||
self,
|
||||
use_tree.span,
|
||||
ResolutionError::
|
||||
SelfImportOnlyInImportListWithNonEmptyPrefix
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Replace `use foo::self;` with `use foo;`
|
||||
source = module_path.pop().unwrap();
|
||||
if rename.is_none() {
|
||||
ident = source.ident;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Disallow `self`
|
||||
if source.ident.name == kw::SelfLower {
|
||||
resolve_error(self,
|
||||
use_tree.span,
|
||||
ResolutionError::SelfImportsOnlyAllowedWithin);
|
||||
}
|
||||
|
||||
// Disallow `use $crate;`
|
||||
if source.ident.name == kw::DollarCrate && module_path.is_empty() {
|
||||
let crate_root = self.resolve_crate_root(source.ident);
|
||||
let crate_name = match crate_root.kind {
|
||||
ModuleKind::Def(.., name) => name,
|
||||
ModuleKind::Block(..) => unreachable!(),
|
||||
};
|
||||
// HACK(eddyb) unclear how good this is, but keeping `$crate`
|
||||
// in `source` breaks `src/test/compile-fail/import-crate-var.rs`,
|
||||
// while the current crate doesn't have a valid `crate_name`.
|
||||
if crate_name != kw::Invalid {
|
||||
// `crate_name` should not be interpreted as relative.
|
||||
module_path.push(Segment {
|
||||
ident: Ident {
|
||||
name: kw::PathRoot,
|
||||
span: source.ident.span,
|
||||
},
|
||||
id: Some(self.session.next_node_id()),
|
||||
});
|
||||
source.ident.name = crate_name;
|
||||
}
|
||||
if rename.is_none() {
|
||||
ident.name = crate_name;
|
||||
}
|
||||
|
||||
self.session.struct_span_warn(item.span, "`$crate` may not be imported")
|
||||
.note("`use $crate;` was erroneously allowed and \
|
||||
will become a hard error in a future release")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
if ident.name == kw::Crate {
|
||||
self.session.span_err(ident.span,
|
||||
"crate root imports need to be explicitly named: \
|
||||
`use crate as name;`");
|
||||
}
|
||||
|
||||
let subclass = SingleImport {
|
||||
source: source.ident,
|
||||
target: ident,
|
||||
source_bindings: PerNS {
|
||||
type_ns: Cell::new(Err(Determinacy::Undetermined)),
|
||||
value_ns: Cell::new(Err(Determinacy::Undetermined)),
|
||||
macro_ns: Cell::new(Err(Determinacy::Undetermined)),
|
||||
},
|
||||
target_bindings: PerNS {
|
||||
type_ns: Cell::new(None),
|
||||
value_ns: Cell::new(None),
|
||||
macro_ns: Cell::new(None),
|
||||
},
|
||||
type_ns_only,
|
||||
nested,
|
||||
};
|
||||
self.add_import_directive(
|
||||
module_path,
|
||||
subclass,
|
||||
use_tree.span,
|
||||
id,
|
||||
item,
|
||||
root_span,
|
||||
item.id,
|
||||
vis,
|
||||
parent_scope,
|
||||
);
|
||||
}
|
||||
ast::UseTreeKind::Glob => {
|
||||
let subclass = GlobImport {
|
||||
is_prelude: attr::contains_name(&item.attrs, sym::prelude_import),
|
||||
max_vis: Cell::new(ty::Visibility::Invisible),
|
||||
};
|
||||
self.add_import_directive(
|
||||
prefix,
|
||||
subclass,
|
||||
use_tree.span,
|
||||
id,
|
||||
item,
|
||||
root_span,
|
||||
item.id,
|
||||
vis,
|
||||
parent_scope,
|
||||
);
|
||||
}
|
||||
ast::UseTreeKind::Nested(ref items) => {
|
||||
// Ensure there is at most one `self` in the list
|
||||
let self_spans = items.iter().filter_map(|&(ref use_tree, _)| {
|
||||
if let ast::UseTreeKind::Simple(..) = use_tree.kind {
|
||||
if use_tree.ident().name == kw::SelfLower {
|
||||
return Some(use_tree.span);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}).collect::<Vec<_>>();
|
||||
if self_spans.len() > 1 {
|
||||
let mut e = resolve_struct_error(self,
|
||||
self_spans[0],
|
||||
ResolutionError::SelfImportCanOnlyAppearOnceInTheList);
|
||||
|
||||
for other_span in self_spans.iter().skip(1) {
|
||||
e.span_label(*other_span, "another `self` import appears here");
|
||||
}
|
||||
|
||||
e.emit();
|
||||
}
|
||||
|
||||
for &(ref tree, id) in items {
|
||||
self.build_reduced_graph_for_use_tree(
|
||||
// This particular use tree
|
||||
tree, id, &prefix, true,
|
||||
// The whole `use` item
|
||||
parent_scope.clone(), item, vis, root_span,
|
||||
);
|
||||
}
|
||||
|
||||
// Empty groups `a::b::{}` are turned into synthetic `self` imports
|
||||
// `a::b::c::{self as _}`, so that their prefixes are correctly
|
||||
// resolved and checked for privacy/stability/etc.
|
||||
if items.is_empty() && !empty_for_self(&prefix) {
|
||||
let new_span = prefix[prefix.len() - 1].ident.span;
|
||||
let tree = ast::UseTree {
|
||||
prefix: ast::Path::from_ident(
|
||||
Ident::new(kw::SelfLower, new_span)
|
||||
),
|
||||
kind: ast::UseTreeKind::Simple(
|
||||
Some(Ident::new(kw::Underscore, new_span)),
|
||||
ast::DUMMY_NODE_ID,
|
||||
ast::DUMMY_NODE_ID,
|
||||
),
|
||||
span: use_tree.span,
|
||||
};
|
||||
self.build_reduced_graph_for_use_tree(
|
||||
// This particular use tree
|
||||
&tree, id, &prefix, true,
|
||||
// The whole `use` item
|
||||
parent_scope, item, ty::Visibility::Invisible, root_span,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs the reduced graph for one item.
|
||||
fn build_reduced_graph_for_item(&mut self, item: &Item, parent_scope: ParentScope<'a>) {
|
||||
let parent = parent_scope.module;
|
||||
let expansion = parent_scope.expansion;
|
||||
let ident = item.ident.gensym_if_underscore();
|
||||
let sp = item.span;
|
||||
let vis = self.resolve_visibility(&item.vis);
|
||||
|
||||
match item.node {
|
||||
ItemKind::Use(ref use_tree) => {
|
||||
self.build_reduced_graph_for_use_tree(
|
||||
// This particular use tree
|
||||
use_tree, item.id, &[], false,
|
||||
// The whole `use` item
|
||||
parent_scope, item, vis, use_tree.span,
|
||||
);
|
||||
}
|
||||
|
||||
ItemKind::ExternCrate(orig_name) => {
|
||||
let module = if orig_name.is_none() && ident.name == kw::SelfLower {
|
||||
self.session
|
||||
.struct_span_err(item.span, "`extern crate self;` requires renaming")
|
||||
.span_suggestion(
|
||||
item.span,
|
||||
"try",
|
||||
"extern crate self as name;".into(),
|
||||
Applicability::HasPlaceholders,
|
||||
)
|
||||
.emit();
|
||||
return;
|
||||
} else if orig_name == Some(kw::SelfLower) {
|
||||
self.graph_root
|
||||
} else {
|
||||
let crate_id = self.crate_loader.process_extern_crate(item, &self.definitions);
|
||||
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
|
||||
};
|
||||
|
||||
self.populate_module_if_necessary(module);
|
||||
if let Some(name) = self.session.parse_sess.injected_crate_name.try_get() {
|
||||
if name.as_str() == ident.name.as_str() {
|
||||
self.injected_crate = Some(module);
|
||||
}
|
||||
}
|
||||
|
||||
let used = self.process_legacy_macro_imports(item, module, &parent_scope);
|
||||
let binding =
|
||||
(module, ty::Visibility::Public, sp, expansion).to_name_binding(self.arenas);
|
||||
let directive = self.arenas.alloc_import_directive(ImportDirective {
|
||||
root_id: item.id,
|
||||
id: item.id,
|
||||
parent_scope,
|
||||
imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))),
|
||||
subclass: ImportDirectiveSubclass::ExternCrate {
|
||||
source: orig_name,
|
||||
target: ident,
|
||||
},
|
||||
has_attributes: !item.attrs.is_empty(),
|
||||
use_span_with_attributes: item.span_with_attributes(),
|
||||
use_span: item.span,
|
||||
root_span: item.span,
|
||||
span: item.span,
|
||||
module_path: Vec::new(),
|
||||
vis: Cell::new(vis),
|
||||
used: Cell::new(used),
|
||||
});
|
||||
self.potentially_unused_imports.push(directive);
|
||||
let imported_binding = self.import(binding, directive);
|
||||
if ptr::eq(self.current_module, self.graph_root) {
|
||||
if let Some(entry) = self.extern_prelude.get(&ident.modern()) {
|
||||
if expansion != ExpnId::root() && orig_name.is_some() &&
|
||||
entry.extern_crate_item.is_none() {
|
||||
self.session.span_err(item.span, "macro-expanded `extern crate` items \
|
||||
cannot shadow names passed with \
|
||||
`--extern`");
|
||||
}
|
||||
}
|
||||
let entry = self.extern_prelude.entry(ident.modern())
|
||||
.or_insert(ExternPreludeEntry {
|
||||
extern_crate_item: None,
|
||||
introduced_by_item: true,
|
||||
});
|
||||
entry.extern_crate_item = Some(imported_binding);
|
||||
if orig_name.is_some() {
|
||||
entry.introduced_by_item = true;
|
||||
}
|
||||
}
|
||||
self.define(parent, ident, TypeNS, imported_binding);
|
||||
}
|
||||
|
||||
ItemKind::GlobalAsm(..) => {}
|
||||
|
||||
ItemKind::Mod(..) if ident.name == kw::Invalid => {} // Crate root
|
||||
|
||||
ItemKind::Mod(..) => {
|
||||
let def_id = self.definitions.local_def_id(item.id);
|
||||
let module_kind = ModuleKind::Def(DefKind::Mod, def_id, ident.name);
|
||||
let module = self.arenas.alloc_module(ModuleData {
|
||||
no_implicit_prelude: parent.no_implicit_prelude || {
|
||||
attr::contains_name(&item.attrs, sym::no_implicit_prelude)
|
||||
},
|
||||
..ModuleData::new(Some(parent), module_kind, def_id, expansion, item.span)
|
||||
});
|
||||
self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
|
||||
self.module_map.insert(def_id, module);
|
||||
|
||||
// Descend into the module.
|
||||
self.current_module = module;
|
||||
}
|
||||
|
||||
// Handled in `rustc_metadata::{native_libs,link_args}`
|
||||
ItemKind::ForeignMod(..) => {}
|
||||
|
||||
// These items live in the value namespace.
|
||||
ItemKind::Static(..) => {
|
||||
let res = Res::Def(DefKind::Static, self.definitions.local_def_id(item.id));
|
||||
self.define(parent, ident, ValueNS, (res, vis, sp, expansion));
|
||||
}
|
||||
ItemKind::Const(..) => {
|
||||
let res = Res::Def(DefKind::Const, self.definitions.local_def_id(item.id));
|
||||
self.define(parent, ident, ValueNS, (res, vis, sp, expansion));
|
||||
}
|
||||
ItemKind::Fn(..) => {
|
||||
let res = Res::Def(DefKind::Fn, self.definitions.local_def_id(item.id));
|
||||
self.define(parent, ident, ValueNS, (res, vis, sp, expansion));
|
||||
|
||||
// Functions introducing procedural macros reserve a slot
|
||||
// in the macro namespace as well (see #52225).
|
||||
self.define_macro(item, expansion, &mut LegacyScope::Empty);
|
||||
}
|
||||
|
||||
// These items live in the type namespace.
|
||||
ItemKind::TyAlias(..) => {
|
||||
let res = Res::Def(DefKind::TyAlias, self.definitions.local_def_id(item.id));
|
||||
self.define(parent, ident, TypeNS, (res, vis, sp, expansion));
|
||||
}
|
||||
|
||||
ItemKind::OpaqueTy(_, _) => {
|
||||
let res = Res::Def(DefKind::OpaqueTy, self.definitions.local_def_id(item.id));
|
||||
self.define(parent, ident, TypeNS, (res, vis, sp, expansion));
|
||||
}
|
||||
|
||||
ItemKind::Enum(ref enum_definition, _) => {
|
||||
let module_kind = ModuleKind::Def(
|
||||
DefKind::Enum,
|
||||
self.definitions.local_def_id(item.id),
|
||||
ident.name,
|
||||
);
|
||||
let module = self.new_module(parent,
|
||||
module_kind,
|
||||
parent.normal_ancestor_id,
|
||||
expansion,
|
||||
item.span);
|
||||
self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
|
||||
|
||||
for variant in &(*enum_definition).variants {
|
||||
self.build_reduced_graph_for_variant(variant, module, vis, expansion);
|
||||
}
|
||||
}
|
||||
|
||||
ItemKind::TraitAlias(..) => {
|
||||
let res = Res::Def(DefKind::TraitAlias, self.definitions.local_def_id(item.id));
|
||||
self.define(parent, ident, TypeNS, (res, vis, sp, expansion));
|
||||
}
|
||||
|
||||
// These items live in both the type and value namespaces.
|
||||
ItemKind::Struct(ref struct_def, _) => {
|
||||
// Define a name in the type namespace.
|
||||
let def_id = self.definitions.local_def_id(item.id);
|
||||
let res = Res::Def(DefKind::Struct, def_id);
|
||||
self.define(parent, ident, TypeNS, (res, vis, sp, expansion));
|
||||
|
||||
let mut ctor_vis = vis;
|
||||
|
||||
let has_non_exhaustive = attr::contains_name(&item.attrs, sym::non_exhaustive);
|
||||
|
||||
// If the structure is marked as non_exhaustive then lower the visibility
|
||||
// to within the crate.
|
||||
if has_non_exhaustive && vis == ty::Visibility::Public {
|
||||
ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
|
||||
}
|
||||
|
||||
// Record field names for error reporting.
|
||||
let field_names = struct_def.fields().iter().filter_map(|field| {
|
||||
let field_vis = self.resolve_visibility(&field.vis);
|
||||
if ctor_vis.is_at_least(field_vis, &*self) {
|
||||
ctor_vis = field_vis;
|
||||
}
|
||||
field.ident.map(|ident| ident.name)
|
||||
}).collect();
|
||||
let item_def_id = self.definitions.local_def_id(item.id);
|
||||
self.insert_field_names(item_def_id, field_names);
|
||||
|
||||
// If this is a tuple or unit struct, define a name
|
||||
// in the value namespace as well.
|
||||
if let Some(ctor_node_id) = struct_def.ctor_id() {
|
||||
let ctor_res = Res::Def(
|
||||
DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(struct_def)),
|
||||
self.definitions.local_def_id(ctor_node_id),
|
||||
);
|
||||
self.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
|
||||
self.struct_constructors.insert(res.def_id(), (ctor_res, ctor_vis));
|
||||
}
|
||||
}
|
||||
|
||||
ItemKind::Union(ref vdata, _) => {
|
||||
let res = Res::Def(DefKind::Union, self.definitions.local_def_id(item.id));
|
||||
self.define(parent, ident, TypeNS, (res, vis, sp, expansion));
|
||||
|
||||
// Record field names for error reporting.
|
||||
let field_names = vdata.fields().iter().filter_map(|field| {
|
||||
self.resolve_visibility(&field.vis);
|
||||
field.ident.map(|ident| ident.name)
|
||||
}).collect();
|
||||
let item_def_id = self.definitions.local_def_id(item.id);
|
||||
self.insert_field_names(item_def_id, field_names);
|
||||
}
|
||||
|
||||
ItemKind::Impl(..) => {}
|
||||
|
||||
ItemKind::Trait(..) => {
|
||||
let def_id = self.definitions.local_def_id(item.id);
|
||||
|
||||
// Add all the items within to a new module.
|
||||
let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name);
|
||||
let module = self.new_module(parent,
|
||||
module_kind,
|
||||
parent.normal_ancestor_id,
|
||||
expansion,
|
||||
item.span);
|
||||
self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
|
||||
self.current_module = module;
|
||||
}
|
||||
|
||||
ItemKind::MacroDef(..) | ItemKind::Mac(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
// Constructs the reduced graph for one variant. Variants exist in the
|
||||
// type and value namespaces.
|
||||
fn build_reduced_graph_for_variant(&mut self,
|
||||
variant: &Variant,
|
||||
parent: Module<'a>,
|
||||
vis: ty::Visibility,
|
||||
expn_id: ExpnId) {
|
||||
let ident = variant.node.ident;
|
||||
|
||||
// Define a name in the type namespace.
|
||||
let def_id = self.definitions.local_def_id(variant.node.id);
|
||||
let res = Res::Def(DefKind::Variant, def_id);
|
||||
self.define(parent, ident, TypeNS, (res, vis, variant.span, expn_id));
|
||||
|
||||
// If the variant is marked as non_exhaustive then lower the visibility to within the
|
||||
// crate.
|
||||
let mut ctor_vis = vis;
|
||||
let has_non_exhaustive = attr::contains_name(&variant.node.attrs, sym::non_exhaustive);
|
||||
if has_non_exhaustive && vis == ty::Visibility::Public {
|
||||
ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
|
||||
}
|
||||
|
||||
// Define a constructor name in the value namespace.
|
||||
// Braced variants, unlike structs, generate unusable names in
|
||||
// value namespace, they are reserved for possible future use.
|
||||
// It's ok to use the variant's id as a ctor id since an
|
||||
// error will be reported on any use of such resolution anyway.
|
||||
let ctor_node_id = variant.node.data.ctor_id().unwrap_or(variant.node.id);
|
||||
let ctor_def_id = self.definitions.local_def_id(ctor_node_id);
|
||||
let ctor_kind = CtorKind::from_ast(&variant.node.data);
|
||||
let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
|
||||
self.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id));
|
||||
}
|
||||
|
||||
/// Constructs the reduced graph for one foreign item.
|
||||
fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem, expn_id: ExpnId) {
|
||||
let (res, ns) = match item.node {
|
||||
ForeignItemKind::Fn(..) => {
|
||||
(Res::Def(DefKind::Fn, self.definitions.local_def_id(item.id)), ValueNS)
|
||||
}
|
||||
ForeignItemKind::Static(..) => {
|
||||
(Res::Def(DefKind::Static, self.definitions.local_def_id(item.id)), ValueNS)
|
||||
}
|
||||
ForeignItemKind::Ty => {
|
||||
(Res::Def(DefKind::ForeignTy, self.definitions.local_def_id(item.id)), TypeNS)
|
||||
}
|
||||
ForeignItemKind::Macro(_) => unreachable!(),
|
||||
};
|
||||
let parent = self.current_module;
|
||||
let vis = self.resolve_visibility(&item.vis);
|
||||
self.define(parent, item.ident, ns, (res, vis, item.span, expn_id));
|
||||
}
|
||||
|
||||
fn build_reduced_graph_for_block(&mut self, block: &Block, expn_id: ExpnId) {
|
||||
let parent = self.current_module;
|
||||
if self.block_needs_anonymous_module(block) {
|
||||
let module = self.new_module(parent,
|
||||
ModuleKind::Block(block.id),
|
||||
parent.normal_ancestor_id,
|
||||
expn_id,
|
||||
block.span);
|
||||
self.block_map.insert(block.id, module);
|
||||
self.current_module = module; // Descend into the block.
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds the reduced graph for a single item in an external crate.
|
||||
fn build_reduced_graph_for_external_crate_res(
|
||||
&mut self,
|
||||
parent: Module<'a>,
|
||||
child: Export<ast::NodeId>,
|
||||
) {
|
||||
let Export { ident, res, vis, span } = child;
|
||||
// FIXME: We shouldn't create the gensym here, it should come from metadata,
|
||||
// but metadata cannot encode gensyms currently, so we create it here.
|
||||
// This is only a guess, two equivalent idents may incorrectly get different gensyms here.
|
||||
let ident = ident.gensym_if_underscore();
|
||||
let expansion = ExpnId::root(); // FIXME(jseyfried) intercrate hygiene
|
||||
match res {
|
||||
Res::Def(kind @ DefKind::Mod, def_id)
|
||||
| Res::Def(kind @ DefKind::Enum, def_id) => {
|
||||
let module = self.new_module(parent,
|
||||
ModuleKind::Def(kind, def_id, ident.name),
|
||||
def_id,
|
||||
expansion,
|
||||
span);
|
||||
self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion));
|
||||
}
|
||||
Res::Def(DefKind::Variant, _)
|
||||
| Res::Def(DefKind::TyAlias, _)
|
||||
| Res::Def(DefKind::ForeignTy, _)
|
||||
| Res::Def(DefKind::OpaqueTy, _)
|
||||
| Res::Def(DefKind::TraitAlias, _)
|
||||
| Res::PrimTy(..)
|
||||
| Res::ToolMod => {
|
||||
self.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion));
|
||||
}
|
||||
Res::Def(DefKind::Fn, _)
|
||||
| Res::Def(DefKind::Static, _)
|
||||
| Res::Def(DefKind::Const, _)
|
||||
| Res::Def(DefKind::Ctor(CtorOf::Variant, ..), _) => {
|
||||
self.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion));
|
||||
}
|
||||
Res::Def(DefKind::Ctor(CtorOf::Struct, ..), def_id) => {
|
||||
self.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion));
|
||||
|
||||
if let Some(struct_def_id) =
|
||||
self.cstore.def_key(def_id).parent
|
||||
.map(|index| DefId { krate: def_id.krate, index: index }) {
|
||||
self.struct_constructors.insert(struct_def_id, (res, vis));
|
||||
}
|
||||
}
|
||||
Res::Def(DefKind::Trait, def_id) => {
|
||||
let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name);
|
||||
let module = self.new_module(parent,
|
||||
module_kind,
|
||||
parent.normal_ancestor_id,
|
||||
expansion,
|
||||
span);
|
||||
self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion));
|
||||
|
||||
for child in self.cstore.item_children_untracked(def_id, self.session) {
|
||||
let res = child.res.map_id(|_| panic!("unexpected id"));
|
||||
let ns = if let Res::Def(DefKind::AssocTy, _) = res {
|
||||
TypeNS
|
||||
} else { ValueNS };
|
||||
self.define(module, child.ident, ns,
|
||||
(res, ty::Visibility::Public, DUMMY_SP, expansion));
|
||||
|
||||
if self.cstore.associated_item_cloned_untracked(child.res.def_id())
|
||||
.method_has_self_argument {
|
||||
self.has_self.insert(res.def_id());
|
||||
}
|
||||
}
|
||||
module.populated.set(true);
|
||||
}
|
||||
Res::Def(DefKind::Struct, def_id) | Res::Def(DefKind::Union, def_id) => {
|
||||
self.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion));
|
||||
|
||||
// Record field names for error reporting.
|
||||
let field_names = self.cstore.struct_field_names_untracked(def_id);
|
||||
self.insert_field_names(def_id, field_names);
|
||||
}
|
||||
Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => {
|
||||
self.define(parent, ident, MacroNS, (res, vis, DUMMY_SP, expansion));
|
||||
}
|
||||
_ => bug!("unexpected resolution: {:?}", res)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_module(&mut self, def_id: DefId) -> Module<'a> {
|
||||
if def_id.krate == LOCAL_CRATE {
|
||||
return self.module_map[&def_id]
|
||||
@@ -787,42 +165,822 @@ pub fn populate_module_if_necessary(&mut self, module: Module<'a>) {
|
||||
let def_id = module.def_id().unwrap();
|
||||
for child in self.cstore.item_children_untracked(def_id, self.session) {
|
||||
let child = child.map_id(|_| panic!("unexpected id"));
|
||||
self.build_reduced_graph_for_external_crate_res(module, child);
|
||||
BuildReducedGraphVisitor { parent_scope: self.dummy_parent_scope(), r: self }
|
||||
.build_reduced_graph_for_external_crate_res(module, child);
|
||||
}
|
||||
module.populated.set(true)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BuildReducedGraphVisitor<'a, 'b> {
|
||||
pub r: &'b mut Resolver<'a>,
|
||||
pub parent_scope: ParentScope<'a>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
||||
fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility {
|
||||
let parent_scope = &self.parent_scope;
|
||||
match vis.node {
|
||||
ast::VisibilityKind::Public => ty::Visibility::Public,
|
||||
ast::VisibilityKind::Crate(..) => {
|
||||
ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
|
||||
}
|
||||
ast::VisibilityKind::Inherited => {
|
||||
ty::Visibility::Restricted(parent_scope.module.normal_ancestor_id)
|
||||
}
|
||||
ast::VisibilityKind::Restricted { ref path, id, .. } => {
|
||||
// For visibilities we are not ready to provide correct implementation of "uniform
|
||||
// paths" right now, so on 2018 edition we only allow module-relative paths for now.
|
||||
// On 2015 edition visibilities are resolved as crate-relative by default,
|
||||
// so we are prepending a root segment if necessary.
|
||||
let ident = path.segments.get(0).expect("empty path in visibility").ident;
|
||||
let crate_root = if ident.is_path_segment_keyword() {
|
||||
None
|
||||
} else if ident.span.rust_2018() {
|
||||
let msg = "relative paths are not supported in visibilities on 2018 edition";
|
||||
self.r.session.struct_span_err(ident.span, msg)
|
||||
.span_suggestion(
|
||||
path.span,
|
||||
"try",
|
||||
format!("crate::{}", path),
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
return ty::Visibility::Public;
|
||||
} else {
|
||||
let ctxt = ident.span.ctxt();
|
||||
Some(Segment::from_ident(Ident::new(
|
||||
kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ctxt)
|
||||
)))
|
||||
};
|
||||
|
||||
let segments = crate_root.into_iter()
|
||||
.chain(path.segments.iter().map(|seg| seg.into())).collect::<Vec<_>>();
|
||||
let expected_found_error = |this: &Self, res: Res| {
|
||||
let path_str = Segment::names_to_string(&segments);
|
||||
struct_span_err!(this.r.session, path.span, E0577,
|
||||
"expected module, found {} `{}`", res.descr(), path_str)
|
||||
.span_label(path.span, "not a module").emit();
|
||||
};
|
||||
match self.r.resolve_path(
|
||||
&segments,
|
||||
Some(TypeNS),
|
||||
parent_scope,
|
||||
true,
|
||||
path.span,
|
||||
CrateLint::SimplePath(id),
|
||||
) {
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
|
||||
let res = module.res().expect("visibility resolved to unnamed block");
|
||||
self.r.record_partial_res(id, PartialRes::new(res));
|
||||
if module.is_normal() {
|
||||
if res == Res::Err {
|
||||
ty::Visibility::Public
|
||||
} else {
|
||||
let vis = ty::Visibility::Restricted(res.def_id());
|
||||
if self.r.is_accessible_from(vis, parent_scope.module) {
|
||||
vis
|
||||
} else {
|
||||
let msg =
|
||||
"visibilities can only be restricted to ancestor modules";
|
||||
self.r.session.span_err(path.span, msg);
|
||||
ty::Visibility::Public
|
||||
}
|
||||
}
|
||||
} else {
|
||||
expected_found_error(self, res);
|
||||
ty::Visibility::Public
|
||||
}
|
||||
}
|
||||
PathResult::Module(..) => {
|
||||
self.r.session.span_err(path.span, "visibility must resolve to a module");
|
||||
ty::Visibility::Public
|
||||
}
|
||||
PathResult::NonModule(partial_res) => {
|
||||
expected_found_error(self, partial_res.base_res());
|
||||
ty::Visibility::Public
|
||||
}
|
||||
PathResult::Failed { span, label, suggestion, .. } => {
|
||||
self.r.report_error(
|
||||
span, ResolutionError::FailedToResolve { label, suggestion }
|
||||
);
|
||||
ty::Visibility::Public
|
||||
}
|
||||
PathResult::Indeterminate => {
|
||||
span_err!(self.r.session, path.span, E0578,
|
||||
"cannot determine resolution for the visibility");
|
||||
ty::Visibility::Public
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_field_names(&mut self, def_id: DefId, field_names: Vec<Name>) {
|
||||
if !field_names.is_empty() {
|
||||
self.r.field_names.insert(def_id, field_names);
|
||||
}
|
||||
}
|
||||
|
||||
fn block_needs_anonymous_module(&mut self, block: &Block) -> bool {
|
||||
// If any statements are items, we need to create an anonymous module
|
||||
block.stmts.iter().any(|statement| match statement.node {
|
||||
StmtKind::Item(_) | StmtKind::Mac(_) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
// Add an import directive to the current module.
|
||||
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,
|
||||
) {
|
||||
let parent_scope = &self.parent_scope;
|
||||
let current_module = parent_scope.module;
|
||||
let directive = self.r.arenas.alloc_import_directive(ImportDirective {
|
||||
parent_scope: parent_scope.clone(),
|
||||
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.r.indeterminate_imports.push(directive);
|
||||
match directive.subclass {
|
||||
SingleImport { target, type_ns_only, .. } => {
|
||||
self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
|
||||
let mut resolution = this.resolution(current_module, target, ns).borrow_mut();
|
||||
resolution.add_single_import(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!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_reduced_graph_for_use_tree(
|
||||
&mut self,
|
||||
// This particular use tree
|
||||
use_tree: &ast::UseTree,
|
||||
id: NodeId,
|
||||
parent_prefix: &[Segment],
|
||||
nested: bool,
|
||||
// The whole `use` item
|
||||
item: &Item,
|
||||
vis: ty::Visibility,
|
||||
root_span: Span,
|
||||
) {
|
||||
debug!("build_reduced_graph_for_use_tree(parent_prefix={:?}, use_tree={:?}, nested={})",
|
||||
parent_prefix, use_tree, nested);
|
||||
|
||||
let mut prefix_iter = parent_prefix.iter().cloned()
|
||||
.chain(use_tree.prefix.segments.iter().map(|seg| seg.into())).peekable();
|
||||
|
||||
// On 2015 edition imports are resolved as crate-relative by default,
|
||||
// so prefixes are prepended with crate root segment if necessary.
|
||||
// The root is prepended lazily, when the first non-empty prefix or terminating glob
|
||||
// appears, so imports in braced groups can have roots prepended independently.
|
||||
let is_glob = if let ast::UseTreeKind::Glob = use_tree.kind { true } else { false };
|
||||
let crate_root = match prefix_iter.peek() {
|
||||
Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.rust_2015() => {
|
||||
Some(seg.ident.span.ctxt())
|
||||
}
|
||||
None if is_glob && use_tree.span.rust_2015() => {
|
||||
Some(use_tree.span.ctxt())
|
||||
}
|
||||
_ => None,
|
||||
}.map(|ctxt| Segment::from_ident(Ident::new(
|
||||
kw::PathRoot, use_tree.prefix.span.shrink_to_lo().with_ctxt(ctxt)
|
||||
)));
|
||||
|
||||
let prefix = crate_root.into_iter().chain(prefix_iter).collect::<Vec<_>>();
|
||||
debug!("build_reduced_graph_for_use_tree: prefix={:?}", prefix);
|
||||
|
||||
let empty_for_self = |prefix: &[Segment]| {
|
||||
prefix.is_empty() ||
|
||||
prefix.len() == 1 && prefix[0].ident.name == kw::PathRoot
|
||||
};
|
||||
match use_tree.kind {
|
||||
ast::UseTreeKind::Simple(rename, ..) => {
|
||||
let mut ident = use_tree.ident().gensym_if_underscore();
|
||||
let mut module_path = prefix;
|
||||
let mut source = module_path.pop().unwrap();
|
||||
let mut type_ns_only = false;
|
||||
|
||||
if nested {
|
||||
// Correctly handle `self`
|
||||
if source.ident.name == kw::SelfLower {
|
||||
type_ns_only = true;
|
||||
|
||||
if empty_for_self(&module_path) {
|
||||
self.r.report_error(
|
||||
use_tree.span,
|
||||
ResolutionError::
|
||||
SelfImportOnlyInImportListWithNonEmptyPrefix
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Replace `use foo::self;` with `use foo;`
|
||||
source = module_path.pop().unwrap();
|
||||
if rename.is_none() {
|
||||
ident = source.ident;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Disallow `self`
|
||||
if source.ident.name == kw::SelfLower {
|
||||
self.r.report_error(
|
||||
use_tree.span, ResolutionError::SelfImportsOnlyAllowedWithin
|
||||
);
|
||||
}
|
||||
|
||||
// Disallow `use $crate;`
|
||||
if source.ident.name == kw::DollarCrate && module_path.is_empty() {
|
||||
let crate_root = self.r.resolve_crate_root(source.ident);
|
||||
let crate_name = match crate_root.kind {
|
||||
ModuleKind::Def(.., name) => name,
|
||||
ModuleKind::Block(..) => unreachable!(),
|
||||
};
|
||||
// HACK(eddyb) unclear how good this is, but keeping `$crate`
|
||||
// in `source` breaks `src/test/compile-fail/import-crate-var.rs`,
|
||||
// while the current crate doesn't have a valid `crate_name`.
|
||||
if crate_name != kw::Invalid {
|
||||
// `crate_name` should not be interpreted as relative.
|
||||
module_path.push(Segment {
|
||||
ident: Ident {
|
||||
name: kw::PathRoot,
|
||||
span: source.ident.span,
|
||||
},
|
||||
id: Some(self.r.session.next_node_id()),
|
||||
});
|
||||
source.ident.name = crate_name;
|
||||
}
|
||||
if rename.is_none() {
|
||||
ident.name = crate_name;
|
||||
}
|
||||
|
||||
self.r.session.struct_span_warn(item.span, "`$crate` may not be imported")
|
||||
.note("`use $crate;` was erroneously allowed and \
|
||||
will become a hard error in a future release")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
if ident.name == kw::Crate {
|
||||
self.r.session.span_err(ident.span,
|
||||
"crate root imports need to be explicitly named: \
|
||||
`use crate as name;`");
|
||||
}
|
||||
|
||||
let subclass = SingleImport {
|
||||
source: source.ident,
|
||||
target: ident,
|
||||
source_bindings: PerNS {
|
||||
type_ns: Cell::new(Err(Determinacy::Undetermined)),
|
||||
value_ns: Cell::new(Err(Determinacy::Undetermined)),
|
||||
macro_ns: Cell::new(Err(Determinacy::Undetermined)),
|
||||
},
|
||||
target_bindings: PerNS {
|
||||
type_ns: Cell::new(None),
|
||||
value_ns: Cell::new(None),
|
||||
macro_ns: Cell::new(None),
|
||||
},
|
||||
type_ns_only,
|
||||
nested,
|
||||
};
|
||||
self.add_import_directive(
|
||||
module_path,
|
||||
subclass,
|
||||
use_tree.span,
|
||||
id,
|
||||
item,
|
||||
root_span,
|
||||
item.id,
|
||||
vis,
|
||||
);
|
||||
}
|
||||
ast::UseTreeKind::Glob => {
|
||||
let subclass = GlobImport {
|
||||
is_prelude: attr::contains_name(&item.attrs, sym::prelude_import),
|
||||
max_vis: Cell::new(ty::Visibility::Invisible),
|
||||
};
|
||||
self.add_import_directive(
|
||||
prefix,
|
||||
subclass,
|
||||
use_tree.span,
|
||||
id,
|
||||
item,
|
||||
root_span,
|
||||
item.id,
|
||||
vis,
|
||||
);
|
||||
}
|
||||
ast::UseTreeKind::Nested(ref items) => {
|
||||
// Ensure there is at most one `self` in the list
|
||||
let self_spans = items.iter().filter_map(|&(ref use_tree, _)| {
|
||||
if let ast::UseTreeKind::Simple(..) = use_tree.kind {
|
||||
if use_tree.ident().name == kw::SelfLower {
|
||||
return Some(use_tree.span);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}).collect::<Vec<_>>();
|
||||
if self_spans.len() > 1 {
|
||||
let mut e = self.r.into_struct_error(
|
||||
self_spans[0],
|
||||
ResolutionError::SelfImportCanOnlyAppearOnceInTheList);
|
||||
|
||||
for other_span in self_spans.iter().skip(1) {
|
||||
e.span_label(*other_span, "another `self` import appears here");
|
||||
}
|
||||
|
||||
e.emit();
|
||||
}
|
||||
|
||||
for &(ref tree, id) in items {
|
||||
self.build_reduced_graph_for_use_tree(
|
||||
// This particular use tree
|
||||
tree, id, &prefix, true,
|
||||
// The whole `use` item
|
||||
item, vis, root_span,
|
||||
);
|
||||
}
|
||||
|
||||
// Empty groups `a::b::{}` are turned into synthetic `self` imports
|
||||
// `a::b::c::{self as _}`, so that their prefixes are correctly
|
||||
// resolved and checked for privacy/stability/etc.
|
||||
if items.is_empty() && !empty_for_self(&prefix) {
|
||||
let new_span = prefix[prefix.len() - 1].ident.span;
|
||||
let tree = ast::UseTree {
|
||||
prefix: ast::Path::from_ident(
|
||||
Ident::new(kw::SelfLower, new_span)
|
||||
),
|
||||
kind: ast::UseTreeKind::Simple(
|
||||
Some(Ident::new(kw::Underscore, new_span)),
|
||||
ast::DUMMY_NODE_ID,
|
||||
ast::DUMMY_NODE_ID,
|
||||
),
|
||||
span: use_tree.span,
|
||||
};
|
||||
self.build_reduced_graph_for_use_tree(
|
||||
// This particular use tree
|
||||
&tree, id, &prefix, true,
|
||||
// The whole `use` item
|
||||
item, ty::Visibility::Invisible, root_span,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs the reduced graph for one item.
|
||||
fn build_reduced_graph_for_item(&mut self, item: &Item) {
|
||||
let parent_scope = &self.parent_scope;
|
||||
let parent = parent_scope.module;
|
||||
let expansion = parent_scope.expansion;
|
||||
let ident = item.ident.gensym_if_underscore();
|
||||
let sp = item.span;
|
||||
let vis = self.resolve_visibility(&item.vis);
|
||||
|
||||
match item.node {
|
||||
ItemKind::Use(ref use_tree) => {
|
||||
self.build_reduced_graph_for_use_tree(
|
||||
// This particular use tree
|
||||
use_tree, item.id, &[], false,
|
||||
// The whole `use` item
|
||||
item, vis, use_tree.span,
|
||||
);
|
||||
}
|
||||
|
||||
ItemKind::ExternCrate(orig_name) => {
|
||||
let module = if orig_name.is_none() && ident.name == kw::SelfLower {
|
||||
self.r.session
|
||||
.struct_span_err(item.span, "`extern crate self;` requires renaming")
|
||||
.span_suggestion(
|
||||
item.span,
|
||||
"try",
|
||||
"extern crate self as name;".into(),
|
||||
Applicability::HasPlaceholders,
|
||||
)
|
||||
.emit();
|
||||
return;
|
||||
} else if orig_name == Some(kw::SelfLower) {
|
||||
self.r.graph_root
|
||||
} else {
|
||||
let crate_id = self.r.crate_loader.process_extern_crate(
|
||||
item, &self.r.definitions
|
||||
);
|
||||
self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
|
||||
};
|
||||
|
||||
self.r.populate_module_if_necessary(module);
|
||||
if let Some(name) = self.r.session.parse_sess.injected_crate_name.try_get() {
|
||||
if name.as_str() == ident.name.as_str() {
|
||||
self.r.injected_crate = Some(module);
|
||||
}
|
||||
}
|
||||
|
||||
let used = self.process_legacy_macro_imports(item, module);
|
||||
let binding =
|
||||
(module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas);
|
||||
let directive = self.r.arenas.alloc_import_directive(ImportDirective {
|
||||
root_id: item.id,
|
||||
id: item.id,
|
||||
parent_scope: self.parent_scope.clone(),
|
||||
imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))),
|
||||
subclass: ImportDirectiveSubclass::ExternCrate {
|
||||
source: orig_name,
|
||||
target: ident,
|
||||
},
|
||||
has_attributes: !item.attrs.is_empty(),
|
||||
use_span_with_attributes: item.span_with_attributes(),
|
||||
use_span: item.span,
|
||||
root_span: item.span,
|
||||
span: item.span,
|
||||
module_path: Vec::new(),
|
||||
vis: Cell::new(vis),
|
||||
used: Cell::new(used),
|
||||
});
|
||||
self.r.potentially_unused_imports.push(directive);
|
||||
let imported_binding = self.r.import(binding, directive);
|
||||
if ptr::eq(parent, self.r.graph_root) {
|
||||
if let Some(entry) = self.r.extern_prelude.get(&ident.modern()) {
|
||||
if expansion != ExpnId::root() && orig_name.is_some() &&
|
||||
entry.extern_crate_item.is_none() {
|
||||
let msg = "macro-expanded `extern crate` items cannot \
|
||||
shadow names passed with `--extern`";
|
||||
self.r.session.span_err(item.span, msg);
|
||||
}
|
||||
}
|
||||
let entry = self.r.extern_prelude.entry(ident.modern())
|
||||
.or_insert(ExternPreludeEntry {
|
||||
extern_crate_item: None,
|
||||
introduced_by_item: true,
|
||||
});
|
||||
entry.extern_crate_item = Some(imported_binding);
|
||||
if orig_name.is_some() {
|
||||
entry.introduced_by_item = true;
|
||||
}
|
||||
}
|
||||
self.r.define(parent, ident, TypeNS, imported_binding);
|
||||
}
|
||||
|
||||
ItemKind::GlobalAsm(..) => {}
|
||||
|
||||
ItemKind::Mod(..) if ident.name == kw::Invalid => {} // Crate root
|
||||
|
||||
ItemKind::Mod(..) => {
|
||||
let def_id = self.r.definitions.local_def_id(item.id);
|
||||
let module_kind = ModuleKind::Def(DefKind::Mod, def_id, ident.name);
|
||||
let module = self.r.arenas.alloc_module(ModuleData {
|
||||
no_implicit_prelude: parent.no_implicit_prelude || {
|
||||
attr::contains_name(&item.attrs, sym::no_implicit_prelude)
|
||||
},
|
||||
..ModuleData::new(Some(parent), module_kind, def_id, expansion, item.span)
|
||||
});
|
||||
self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
|
||||
self.r.module_map.insert(def_id, module);
|
||||
|
||||
// Descend into the module.
|
||||
self.parent_scope.module = module;
|
||||
}
|
||||
|
||||
// Handled in `rustc_metadata::{native_libs,link_args}`
|
||||
ItemKind::ForeignMod(..) => {}
|
||||
|
||||
// These items live in the value namespace.
|
||||
ItemKind::Static(..) => {
|
||||
let res = Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id));
|
||||
self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
|
||||
}
|
||||
ItemKind::Const(..) => {
|
||||
let res = Res::Def(DefKind::Const, self.r.definitions.local_def_id(item.id));
|
||||
self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
|
||||
}
|
||||
ItemKind::Fn(..) => {
|
||||
let res = Res::Def(DefKind::Fn, self.r.definitions.local_def_id(item.id));
|
||||
self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
|
||||
|
||||
// Functions introducing procedural macros reserve a slot
|
||||
// in the macro namespace as well (see #52225).
|
||||
self.define_macro(item);
|
||||
}
|
||||
|
||||
// These items live in the type namespace.
|
||||
ItemKind::TyAlias(..) => {
|
||||
let res = Res::Def(DefKind::TyAlias, self.r.definitions.local_def_id(item.id));
|
||||
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
|
||||
}
|
||||
|
||||
ItemKind::OpaqueTy(_, _) => {
|
||||
let res = Res::Def(DefKind::OpaqueTy, self.r.definitions.local_def_id(item.id));
|
||||
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
|
||||
}
|
||||
|
||||
ItemKind::Enum(ref enum_definition, _) => {
|
||||
let module_kind = ModuleKind::Def(
|
||||
DefKind::Enum,
|
||||
self.r.definitions.local_def_id(item.id),
|
||||
ident.name,
|
||||
);
|
||||
let module = self.r.new_module(parent,
|
||||
module_kind,
|
||||
parent.normal_ancestor_id,
|
||||
expansion,
|
||||
item.span);
|
||||
self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
|
||||
|
||||
for variant in &(*enum_definition).variants {
|
||||
self.build_reduced_graph_for_variant(variant, module, vis, expansion);
|
||||
}
|
||||
}
|
||||
|
||||
ItemKind::TraitAlias(..) => {
|
||||
let res = Res::Def(DefKind::TraitAlias, self.r.definitions.local_def_id(item.id));
|
||||
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
|
||||
}
|
||||
|
||||
// These items live in both the type and value namespaces.
|
||||
ItemKind::Struct(ref struct_def, _) => {
|
||||
// Define a name in the type namespace.
|
||||
let def_id = self.r.definitions.local_def_id(item.id);
|
||||
let res = Res::Def(DefKind::Struct, def_id);
|
||||
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
|
||||
|
||||
let mut ctor_vis = vis;
|
||||
|
||||
let has_non_exhaustive = attr::contains_name(&item.attrs, sym::non_exhaustive);
|
||||
|
||||
// If the structure is marked as non_exhaustive then lower the visibility
|
||||
// to within the crate.
|
||||
if has_non_exhaustive && vis == ty::Visibility::Public {
|
||||
ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
|
||||
}
|
||||
|
||||
// Record field names for error reporting.
|
||||
let field_names = struct_def.fields().iter().filter_map(|field| {
|
||||
let field_vis = self.resolve_visibility(&field.vis);
|
||||
if ctor_vis.is_at_least(field_vis, &*self.r) {
|
||||
ctor_vis = field_vis;
|
||||
}
|
||||
field.ident.map(|ident| ident.name)
|
||||
}).collect();
|
||||
let item_def_id = self.r.definitions.local_def_id(item.id);
|
||||
self.insert_field_names(item_def_id, field_names);
|
||||
|
||||
// If this is a tuple or unit struct, define a name
|
||||
// in the value namespace as well.
|
||||
if let Some(ctor_node_id) = struct_def.ctor_id() {
|
||||
let ctor_res = Res::Def(
|
||||
DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(struct_def)),
|
||||
self.r.definitions.local_def_id(ctor_node_id),
|
||||
);
|
||||
self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
|
||||
self.r.struct_constructors.insert(res.def_id(), (ctor_res, ctor_vis));
|
||||
}
|
||||
}
|
||||
|
||||
ItemKind::Union(ref vdata, _) => {
|
||||
let res = Res::Def(DefKind::Union, self.r.definitions.local_def_id(item.id));
|
||||
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
|
||||
|
||||
// Record field names for error reporting.
|
||||
let field_names = vdata.fields().iter().filter_map(|field| {
|
||||
self.resolve_visibility(&field.vis);
|
||||
field.ident.map(|ident| ident.name)
|
||||
}).collect();
|
||||
let item_def_id = self.r.definitions.local_def_id(item.id);
|
||||
self.insert_field_names(item_def_id, field_names);
|
||||
}
|
||||
|
||||
ItemKind::Impl(.., ref impl_items) => {
|
||||
for impl_item in impl_items {
|
||||
self.resolve_visibility(&impl_item.vis);
|
||||
}
|
||||
}
|
||||
|
||||
ItemKind::Trait(..) => {
|
||||
let def_id = self.r.definitions.local_def_id(item.id);
|
||||
|
||||
// Add all the items within to a new module.
|
||||
let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name);
|
||||
let module = self.r.new_module(parent,
|
||||
module_kind,
|
||||
parent.normal_ancestor_id,
|
||||
expansion,
|
||||
item.span);
|
||||
self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
|
||||
self.parent_scope.module = module;
|
||||
}
|
||||
|
||||
ItemKind::MacroDef(..) | ItemKind::Mac(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
// Constructs the reduced graph for one variant. Variants exist in the
|
||||
// type and value namespaces.
|
||||
fn build_reduced_graph_for_variant(&mut self,
|
||||
variant: &Variant,
|
||||
parent: Module<'a>,
|
||||
vis: ty::Visibility,
|
||||
expn_id: ExpnId) {
|
||||
let ident = variant.node.ident;
|
||||
|
||||
// Define a name in the type namespace.
|
||||
let def_id = self.r.definitions.local_def_id(variant.node.id);
|
||||
let res = Res::Def(DefKind::Variant, def_id);
|
||||
self.r.define(parent, ident, TypeNS, (res, vis, variant.span, expn_id));
|
||||
|
||||
// If the variant is marked as non_exhaustive then lower the visibility to within the
|
||||
// crate.
|
||||
let mut ctor_vis = vis;
|
||||
let has_non_exhaustive = attr::contains_name(&variant.node.attrs, sym::non_exhaustive);
|
||||
if has_non_exhaustive && vis == ty::Visibility::Public {
|
||||
ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
|
||||
}
|
||||
|
||||
// Define a constructor name in the value namespace.
|
||||
// Braced variants, unlike structs, generate unusable names in
|
||||
// value namespace, they are reserved for possible future use.
|
||||
// It's ok to use the variant's id as a ctor id since an
|
||||
// error will be reported on any use of such resolution anyway.
|
||||
let ctor_node_id = variant.node.data.ctor_id().unwrap_or(variant.node.id);
|
||||
let ctor_def_id = self.r.definitions.local_def_id(ctor_node_id);
|
||||
let ctor_kind = CtorKind::from_ast(&variant.node.data);
|
||||
let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
|
||||
self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id));
|
||||
}
|
||||
|
||||
/// Constructs the reduced graph for one foreign item.
|
||||
fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem) {
|
||||
let (res, ns) = match item.node {
|
||||
ForeignItemKind::Fn(..) => {
|
||||
(Res::Def(DefKind::Fn, self.r.definitions.local_def_id(item.id)), ValueNS)
|
||||
}
|
||||
ForeignItemKind::Static(..) => {
|
||||
(Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id)), ValueNS)
|
||||
}
|
||||
ForeignItemKind::Ty => {
|
||||
(Res::Def(DefKind::ForeignTy, self.r.definitions.local_def_id(item.id)), TypeNS)
|
||||
}
|
||||
ForeignItemKind::Macro(_) => unreachable!(),
|
||||
};
|
||||
let parent = self.parent_scope.module;
|
||||
let expansion = self.parent_scope.expansion;
|
||||
let vis = self.resolve_visibility(&item.vis);
|
||||
self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion));
|
||||
}
|
||||
|
||||
fn build_reduced_graph_for_block(&mut self, block: &Block) {
|
||||
let parent = self.parent_scope.module;
|
||||
let expansion = self.parent_scope.expansion;
|
||||
if self.block_needs_anonymous_module(block) {
|
||||
let module = self.r.new_module(parent,
|
||||
ModuleKind::Block(block.id),
|
||||
parent.normal_ancestor_id,
|
||||
expansion,
|
||||
block.span);
|
||||
self.r.block_map.insert(block.id, module);
|
||||
self.parent_scope.module = module; // Descend into the block.
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds the reduced graph for a single item in an external crate.
|
||||
fn build_reduced_graph_for_external_crate_res(
|
||||
&mut self,
|
||||
parent: Module<'a>,
|
||||
child: Export<ast::NodeId>,
|
||||
) {
|
||||
let Export { ident, res, vis, span } = child;
|
||||
// FIXME: We shouldn't create the gensym here, it should come from metadata,
|
||||
// but metadata cannot encode gensyms currently, so we create it here.
|
||||
// This is only a guess, two equivalent idents may incorrectly get different gensyms here.
|
||||
let ident = ident.gensym_if_underscore();
|
||||
let expansion = ExpnId::root(); // FIXME(jseyfried) intercrate hygiene
|
||||
match res {
|
||||
Res::Def(kind @ DefKind::Mod, def_id)
|
||||
| Res::Def(kind @ DefKind::Enum, def_id) => {
|
||||
let module = self.r.new_module(parent,
|
||||
ModuleKind::Def(kind, def_id, ident.name),
|
||||
def_id,
|
||||
expansion,
|
||||
span);
|
||||
self.r.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion));
|
||||
}
|
||||
Res::Def(DefKind::Variant, _)
|
||||
| Res::Def(DefKind::TyAlias, _)
|
||||
| Res::Def(DefKind::ForeignTy, _)
|
||||
| Res::Def(DefKind::OpaqueTy, _)
|
||||
| Res::Def(DefKind::TraitAlias, _)
|
||||
| Res::PrimTy(..)
|
||||
| Res::ToolMod => {
|
||||
self.r.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion));
|
||||
}
|
||||
Res::Def(DefKind::Fn, _)
|
||||
| Res::Def(DefKind::Static, _)
|
||||
| Res::Def(DefKind::Const, _)
|
||||
| Res::Def(DefKind::Ctor(CtorOf::Variant, ..), _) => {
|
||||
self.r.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion));
|
||||
}
|
||||
Res::Def(DefKind::Ctor(CtorOf::Struct, ..), def_id) => {
|
||||
self.r.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion));
|
||||
|
||||
if let Some(struct_def_id) =
|
||||
self.r.cstore.def_key(def_id).parent
|
||||
.map(|index| DefId { krate: def_id.krate, index: index }) {
|
||||
self.r.struct_constructors.insert(struct_def_id, (res, vis));
|
||||
}
|
||||
}
|
||||
Res::Def(DefKind::Trait, def_id) => {
|
||||
let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name);
|
||||
let module = self.r.new_module(parent,
|
||||
module_kind,
|
||||
parent.normal_ancestor_id,
|
||||
expansion,
|
||||
span);
|
||||
self.r.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion));
|
||||
|
||||
for child in self.r.cstore.item_children_untracked(def_id, self.r.session) {
|
||||
let res = child.res.map_id(|_| panic!("unexpected id"));
|
||||
let ns = if let Res::Def(DefKind::AssocTy, _) = res {
|
||||
TypeNS
|
||||
} else { ValueNS };
|
||||
self.r.define(module, child.ident, ns,
|
||||
(res, ty::Visibility::Public, DUMMY_SP, expansion));
|
||||
|
||||
if self.r.cstore.associated_item_cloned_untracked(child.res.def_id())
|
||||
.method_has_self_argument {
|
||||
self.r.has_self.insert(res.def_id());
|
||||
}
|
||||
}
|
||||
module.populated.set(true);
|
||||
}
|
||||
Res::Def(DefKind::Struct, def_id) | Res::Def(DefKind::Union, def_id) => {
|
||||
self.r.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion));
|
||||
|
||||
// Record field names for error reporting.
|
||||
let field_names = self.r.cstore.struct_field_names_untracked(def_id);
|
||||
self.insert_field_names(def_id, field_names);
|
||||
}
|
||||
Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => {
|
||||
self.r.define(parent, ident, MacroNS, (res, vis, DUMMY_SP, expansion));
|
||||
}
|
||||
_ => bug!("unexpected resolution: {:?}", res)
|
||||
}
|
||||
}
|
||||
|
||||
fn legacy_import_macro(&mut self,
|
||||
name: Name,
|
||||
binding: &'a NameBinding<'a>,
|
||||
span: Span,
|
||||
allow_shadowing: bool) {
|
||||
if self.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing {
|
||||
if self.r.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing {
|
||||
let msg = format!("`{}` is already in scope", name);
|
||||
let note =
|
||||
"macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";
|
||||
self.session.struct_span_err(span, &msg).note(note).emit();
|
||||
self.r.session.struct_span_err(span, &msg).note(note).emit();
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if we should consider the underlying `extern crate` to be used.
|
||||
fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>,
|
||||
parent_scope: &ParentScope<'a>) -> bool {
|
||||
fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>) -> bool {
|
||||
let mut import_all = None;
|
||||
let mut single_imports = Vec::new();
|
||||
for attr in &item.attrs {
|
||||
if attr.check_name(sym::macro_use) {
|
||||
if self.current_module.parent.is_some() {
|
||||
span_err!(self.session, item.span, E0468,
|
||||
if self.parent_scope.module.parent.is_some() {
|
||||
span_err!(self.r.session, item.span, E0468,
|
||||
"an `extern crate` loading macros must be at the crate root");
|
||||
}
|
||||
if let ItemKind::ExternCrate(Some(orig_name)) = item.node {
|
||||
if orig_name == kw::SelfLower {
|
||||
self.session.span_err(attr.span,
|
||||
self.r.session.span_err(attr.span,
|
||||
"`macro_use` is not supported on `extern crate self`");
|
||||
}
|
||||
}
|
||||
let ill_formed = |span| span_err!(self.session, span, E0466, "bad macro import");
|
||||
let ill_formed = |span| span_err!(self.r.session, span, E0466, "bad macro import");
|
||||
match attr.meta() {
|
||||
Some(meta) => match meta.node {
|
||||
MetaItemKind::Word => {
|
||||
@@ -842,11 +1000,11 @@ fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>,
|
||||
}
|
||||
}
|
||||
|
||||
let arenas = self.arenas;
|
||||
let macro_use_directive = |span| arenas.alloc_import_directive(ImportDirective {
|
||||
let macro_use_directive =
|
||||
|this: &Self, span| this.r.arenas.alloc_import_directive(ImportDirective {
|
||||
root_id: item.id,
|
||||
id: item.id,
|
||||
parent_scope: parent_scope.clone(),
|
||||
parent_scope: this.parent_scope.clone(),
|
||||
imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))),
|
||||
subclass: ImportDirectiveSubclass::MacroUse,
|
||||
use_span_with_attributes: item.span_with_attributes(),
|
||||
@@ -859,32 +1017,32 @@ fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>,
|
||||
used: Cell::new(false),
|
||||
});
|
||||
|
||||
let allow_shadowing = parent_scope.expansion == ExpnId::root();
|
||||
let allow_shadowing = self.parent_scope.expansion == ExpnId::root();
|
||||
if let Some(span) = import_all {
|
||||
let directive = macro_use_directive(span);
|
||||
self.potentially_unused_imports.push(directive);
|
||||
let directive = macro_use_directive(self, span);
|
||||
self.r.potentially_unused_imports.push(directive);
|
||||
module.for_each_child(|ident, ns, binding| if ns == MacroNS {
|
||||
let imported_binding = self.import(binding, directive);
|
||||
let imported_binding = self.r.import(binding, directive);
|
||||
self.legacy_import_macro(ident.name, imported_binding, span, allow_shadowing);
|
||||
});
|
||||
} else {
|
||||
for ident in single_imports.iter().cloned() {
|
||||
let result = self.resolve_ident_in_module(
|
||||
let result = self.r.resolve_ident_in_module(
|
||||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
MacroNS,
|
||||
None,
|
||||
&self.parent_scope,
|
||||
false,
|
||||
ident.span,
|
||||
);
|
||||
if let Ok(binding) = result {
|
||||
let directive = macro_use_directive(ident.span);
|
||||
self.potentially_unused_imports.push(directive);
|
||||
let imported_binding = self.import(binding, directive);
|
||||
let directive = macro_use_directive(self, ident.span);
|
||||
self.r.potentially_unused_imports.push(directive);
|
||||
let imported_binding = self.r.import(binding, directive);
|
||||
self.legacy_import_macro(ident.name, imported_binding,
|
||||
ident.span, allow_shadowing);
|
||||
} else {
|
||||
span_err!(self.session, ident.span, E0469, "imported macro not found");
|
||||
span_err!(self.r.session, ident.span, E0469, "imported macro not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -896,7 +1054,7 @@ fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
|
||||
for attr in attrs {
|
||||
if attr.check_name(sym::macro_escape) {
|
||||
let msg = "macro_escape is a deprecated synonym for macro_use";
|
||||
let mut err = self.session.struct_span_warn(attr.span, msg);
|
||||
let mut err = self.r.session.struct_span_warn(attr.span, msg);
|
||||
if let ast::AttrStyle::Inner = attr.style {
|
||||
err.help("consider an outer attribute, `#[macro_use]` mod ...").emit();
|
||||
} else {
|
||||
@@ -907,42 +1065,106 @@ fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
|
||||
}
|
||||
|
||||
if !attr.is_word() {
|
||||
self.session.span_err(attr.span, "arguments to macro_use are not allowed here");
|
||||
self.r.session.span_err(attr.span, "arguments to macro_use are not allowed here");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BuildReducedGraphVisitor<'a, 'b> {
|
||||
pub resolver: &'a mut Resolver<'b>,
|
||||
pub current_legacy_scope: LegacyScope<'b>,
|
||||
pub expansion: ExpnId,
|
||||
}
|
||||
|
||||
impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
||||
fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> {
|
||||
fn visit_invoc(&mut self, id: ast::NodeId) -> &'a InvocationData<'a> {
|
||||
let invoc_id = id.placeholder_to_expn_id();
|
||||
|
||||
self.resolver.current_module.unresolved_invocations.borrow_mut().insert(invoc_id);
|
||||
self.parent_scope.module.unresolved_invocations.borrow_mut().insert(invoc_id);
|
||||
|
||||
let invocation_data = self.resolver.arenas.alloc_invocation_data(InvocationData {
|
||||
module: self.resolver.current_module,
|
||||
parent_legacy_scope: self.current_legacy_scope,
|
||||
let invocation_data = self.r.arenas.alloc_invocation_data(InvocationData {
|
||||
module: self.parent_scope.module,
|
||||
parent_legacy_scope: self.parent_scope.legacy,
|
||||
output_legacy_scope: Cell::new(None),
|
||||
});
|
||||
let old_invocation_data = self.resolver.invocations.insert(invoc_id, invocation_data);
|
||||
let old_invocation_data = self.r.invocations.insert(invoc_id, invocation_data);
|
||||
assert!(old_invocation_data.is_none(), "invocation data is reset for an invocation");
|
||||
|
||||
invocation_data
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
fn define_macro(&mut self, item: &ast::Item) -> LegacyScope<'a> {
|
||||
let parent_scope = &self.parent_scope;
|
||||
let expansion = parent_scope.expansion;
|
||||
let (ext, ident, span, is_legacy) = match &item.node {
|
||||
ItemKind::MacroDef(def) => {
|
||||
let ext = self.r.compile_macro(item, self.r.session.edition());
|
||||
(ext, item.ident, item.span, def.legacy)
|
||||
}
|
||||
ItemKind::Fn(..) => match Self::proc_macro_stub(item) {
|
||||
Some((macro_kind, ident, span)) => {
|
||||
self.r.proc_macro_stubs.insert(item.id);
|
||||
(self.r.dummy_ext(macro_kind), ident, span, false)
|
||||
}
|
||||
None => return parent_scope.legacy,
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let def_id = self.r.definitions.local_def_id(item.id);
|
||||
let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id);
|
||||
self.r.macro_map.insert(def_id, ext);
|
||||
self.r.local_macro_def_scopes.insert(item.id, parent_scope.module);
|
||||
|
||||
if is_legacy {
|
||||
let ident = ident.modern();
|
||||
self.r.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.r.arenas);
|
||||
self.r.set_binding_parent_module(binding, parent_scope.module);
|
||||
self.r.all_macros.insert(ident.name, res);
|
||||
if is_macro_export {
|
||||
let module = self.r.graph_root;
|
||||
self.r.define(module, ident, MacroNS,
|
||||
(res, vis, span, expansion, IsMacroExport));
|
||||
} else {
|
||||
self.r.check_reserved_macro_name(ident, res);
|
||||
self.r.unused_macros.insert(item.id, span);
|
||||
}
|
||||
LegacyScope::Binding(self.r.arenas.alloc_legacy_binding(LegacyBinding {
|
||||
parent_legacy_scope: parent_scope.legacy, binding, ident
|
||||
}))
|
||||
} else {
|
||||
let module = parent_scope.module;
|
||||
let vis = self.resolve_visibility(&item.vis);
|
||||
if vis != ty::Visibility::Public {
|
||||
self.r.unused_macros.insert(item.id, span);
|
||||
}
|
||||
self.r.define(module, ident, MacroNS, (res, vis, span, expansion));
|
||||
self.parent_scope.legacy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! method {
|
||||
($visit:ident: $ty:ty, $invoc:path, $walk:ident) => {
|
||||
fn $visit(&mut self, node: &'a $ty) {
|
||||
fn $visit(&mut self, node: &'b $ty) {
|
||||
if let $invoc(..) = node.node {
|
||||
self.visit_invoc(node.id);
|
||||
} else {
|
||||
@@ -952,71 +1174,65 @@ fn $visit(&mut self, node: &'a $ty) {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
|
||||
impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
|
||||
method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item);
|
||||
method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr);
|
||||
method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat);
|
||||
method!(visit_ty: ast::Ty, ast::TyKind::Mac, walk_ty);
|
||||
|
||||
fn visit_item(&mut self, item: &'a Item) {
|
||||
fn visit_item(&mut self, item: &'b Item) {
|
||||
let macro_use = match item.node {
|
||||
ItemKind::MacroDef(..) => {
|
||||
self.resolver.define_macro(item, self.expansion, &mut self.current_legacy_scope);
|
||||
self.parent_scope.legacy = self.define_macro(item);
|
||||
return
|
||||
}
|
||||
ItemKind::Mac(..) => {
|
||||
self.current_legacy_scope = LegacyScope::Invocation(self.visit_invoc(item.id));
|
||||
self.parent_scope.legacy = LegacyScope::Invocation(self.visit_invoc(item.id));
|
||||
return
|
||||
}
|
||||
ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs),
|
||||
ItemKind::Mod(..) => self.contains_macro_use(&item.attrs),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let orig_current_module = self.resolver.current_module;
|
||||
let orig_current_legacy_scope = self.current_legacy_scope;
|
||||
let parent_scope = ParentScope {
|
||||
module: self.resolver.current_module,
|
||||
expansion: self.expansion,
|
||||
legacy: self.current_legacy_scope,
|
||||
derives: Vec::new(),
|
||||
};
|
||||
self.resolver.build_reduced_graph_for_item(item, parent_scope);
|
||||
let orig_current_module = self.parent_scope.module;
|
||||
let orig_current_legacy_scope = self.parent_scope.legacy;
|
||||
self.build_reduced_graph_for_item(item);
|
||||
visit::walk_item(self, item);
|
||||
self.resolver.current_module = orig_current_module;
|
||||
self.parent_scope.module = orig_current_module;
|
||||
if !macro_use {
|
||||
self.current_legacy_scope = orig_current_legacy_scope;
|
||||
self.parent_scope.legacy = orig_current_legacy_scope;
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, stmt: &'a ast::Stmt) {
|
||||
fn visit_stmt(&mut self, stmt: &'b ast::Stmt) {
|
||||
if let ast::StmtKind::Mac(..) = stmt.node {
|
||||
self.current_legacy_scope = LegacyScope::Invocation(self.visit_invoc(stmt.id));
|
||||
self.parent_scope.legacy = LegacyScope::Invocation(self.visit_invoc(stmt.id));
|
||||
} else {
|
||||
visit::walk_stmt(self, stmt);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) {
|
||||
fn visit_foreign_item(&mut self, foreign_item: &'b ForeignItem) {
|
||||
if let ForeignItemKind::Macro(_) = foreign_item.node {
|
||||
self.visit_invoc(foreign_item.id);
|
||||
return;
|
||||
}
|
||||
|
||||
self.resolver.build_reduced_graph_for_foreign_item(foreign_item, self.expansion);
|
||||
self.build_reduced_graph_for_foreign_item(foreign_item);
|
||||
visit::walk_foreign_item(self, foreign_item);
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, block: &'a Block) {
|
||||
let orig_current_module = self.resolver.current_module;
|
||||
let orig_current_legacy_scope = self.current_legacy_scope;
|
||||
self.resolver.build_reduced_graph_for_block(block, self.expansion);
|
||||
fn visit_block(&mut self, block: &'b Block) {
|
||||
let orig_current_module = self.parent_scope.module;
|
||||
let orig_current_legacy_scope = self.parent_scope.legacy;
|
||||
self.build_reduced_graph_for_block(block);
|
||||
visit::walk_block(self, block);
|
||||
self.resolver.current_module = orig_current_module;
|
||||
self.current_legacy_scope = orig_current_legacy_scope;
|
||||
self.parent_scope.module = orig_current_module;
|
||||
self.parent_scope.legacy = orig_current_legacy_scope;
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, item: &'a TraitItem) {
|
||||
let parent = self.resolver.current_module;
|
||||
fn visit_trait_item(&mut self, item: &'b TraitItem) {
|
||||
let parent = self.parent_scope.module;
|
||||
|
||||
if let TraitItemKind::Macro(_) = item.node {
|
||||
self.visit_invoc(item.id);
|
||||
@@ -1024,12 +1240,12 @@ fn visit_trait_item(&mut self, item: &'a TraitItem) {
|
||||
}
|
||||
|
||||
// Add the item to the trait info.
|
||||
let item_def_id = self.resolver.definitions.local_def_id(item.id);
|
||||
let item_def_id = self.r.definitions.local_def_id(item.id);
|
||||
let (res, ns) = match item.node {
|
||||
TraitItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS),
|
||||
TraitItemKind::Method(ref sig, _) => {
|
||||
if sig.decl.has_self() {
|
||||
self.resolver.has_self.insert(item_def_id);
|
||||
self.r.has_self.insert(item_def_id);
|
||||
}
|
||||
(Res::Def(DefKind::Method, item_def_id), ValueNS)
|
||||
}
|
||||
@@ -1038,11 +1254,12 @@ fn visit_trait_item(&mut self, item: &'a TraitItem) {
|
||||
};
|
||||
|
||||
let vis = ty::Visibility::Public;
|
||||
self.resolver.define(parent, item.ident, ns, (res, vis, item.span, self.expansion));
|
||||
let expansion = self.parent_scope.expansion;
|
||||
self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion));
|
||||
|
||||
self.resolver.current_module = parent.parent.unwrap(); // nearest normal ancestor
|
||||
self.parent_scope.module = parent.parent.unwrap(); // nearest normal ancestor
|
||||
visit::walk_trait_item(self, item);
|
||||
self.resolver.current_module = parent;
|
||||
self.parent_scope.module = parent;
|
||||
}
|
||||
|
||||
fn visit_token(&mut self, t: Token) {
|
||||
@@ -1055,17 +1272,10 @@ fn visit_token(&mut self, t: Token) {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
|
||||
fn visit_attribute(&mut self, attr: &'b ast::Attribute) {
|
||||
if !attr.is_sugared_doc && is_builtin_attr(attr) {
|
||||
let parent_scope = ParentScope {
|
||||
module: self.resolver.current_module.nearest_item_scope(),
|
||||
expansion: self.expansion,
|
||||
legacy: self.current_legacy_scope,
|
||||
// Let's hope discerning built-in attributes from derive helpers is not necessary
|
||||
derives: Vec::new(),
|
||||
};
|
||||
parent_scope.module.builtin_attrs.borrow_mut().push((
|
||||
attr.path.segments[0].ident, parent_scope
|
||||
self.parent_scope.module.builtin_attrs.borrow_mut().push((
|
||||
attr.path.segments[0].ident, self.parent_scope.clone()
|
||||
));
|
||||
}
|
||||
visit::walk_attribute(self, attr);
|
||||
|
||||
@@ -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 @@ fn add(&mut self, id: ast::NodeId) {
|
||||
}
|
||||
|
||||
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 @@ fn check_import(&mut self, id: ast::NodeId) {
|
||||
} 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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+290
-659
@@ -2,55 +2,63 @@
|
||||
|
||||
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
|
||||
use log::debug;
|
||||
use rustc::hir::def::{self, DefKind, CtorKind, NonMacroAttrKind};
|
||||
use rustc::bug;
|
||||
use rustc::hir::def::{self, DefKind, NonMacroAttrKind};
|
||||
use rustc::hir::def::Namespace::{self, *};
|
||||
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
|
||||
use rustc::hir::PrimTy;
|
||||
use rustc::session::{Session, config::nightly_options};
|
||||
use rustc::session::Session;
|
||||
use rustc::ty::{self, DefIdTree};
|
||||
use rustc::util::nodemap::FxHashSet;
|
||||
use syntax::ast::{self, Expr, ExprKind, Ident, NodeId, Path, Ty, TyKind};
|
||||
use syntax::ast::{self, Ident, Path};
|
||||
use syntax::ext::base::MacroKind;
|
||||
use syntax::feature_gate::BUILTIN_ATTRIBUTES;
|
||||
use syntax::source_map::SourceMap;
|
||||
use syntax::struct_span_err;
|
||||
use syntax::symbol::{Symbol, kw};
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
use syntax_pos::{BytePos, Span};
|
||||
use syntax_pos::{BytePos, Span, MultiSpan};
|
||||
|
||||
use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
|
||||
use crate::{is_self_type, is_self_value, path_names_to_string, KNOWN_TOOLS};
|
||||
use crate::{CrateLint, LegacyScope, Module, ModuleKind, ModuleOrUniformRoot};
|
||||
use crate::{PathResult, PathSource, ParentScope, Resolver, RibKind, Scope, ScopeSet, Segment};
|
||||
use crate::{path_names_to_string, KNOWN_TOOLS};
|
||||
use crate::{CrateLint, LegacyScope, Module, ModuleOrUniformRoot};
|
||||
use crate::{PathResult, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Segment};
|
||||
|
||||
type Res = def::Res<ast::NodeId>;
|
||||
|
||||
/// A vector of spans and replacements, a message and applicability.
|
||||
crate type Suggestion = (Vec<(Span, String)>, String, Applicability);
|
||||
|
||||
/// A field or associated item from self type suggested in case of resolution failure.
|
||||
enum AssocSuggestion {
|
||||
Field,
|
||||
MethodWithSelf,
|
||||
AssocItem,
|
||||
}
|
||||
|
||||
struct TypoSuggestion {
|
||||
candidate: Symbol,
|
||||
res: Res,
|
||||
crate struct TypoSuggestion {
|
||||
pub candidate: Symbol,
|
||||
pub res: Res,
|
||||
}
|
||||
|
||||
impl TypoSuggestion {
|
||||
fn from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
|
||||
crate fn from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
|
||||
TypoSuggestion { candidate, res }
|
||||
}
|
||||
}
|
||||
|
||||
/// A free importable items suggested in case of resolution failure.
|
||||
crate struct ImportSuggestion {
|
||||
did: Option<DefId>,
|
||||
pub did: Option<DefId>,
|
||||
pub path: Path,
|
||||
}
|
||||
|
||||
fn add_typo_suggestion(
|
||||
/// Adjust the impl span so that just the `impl` keyword is taken by removing
|
||||
/// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "impl"`) and
|
||||
/// everything after the first whitespace (`"impl Iterator for A" -> "impl"`).
|
||||
///
|
||||
/// *Attention*: the method used is very fragile since it essentially duplicates the work of the
|
||||
/// parser. If you need to use this function or something similar, please consider updating the
|
||||
/// `source_map` functions and this function to something more robust.
|
||||
fn reduce_impl_span_to_impl_keyword(cm: &SourceMap, impl_span: Span) -> Span {
|
||||
let impl_span = cm.span_until_char(impl_span, '<');
|
||||
let impl_span = cm.span_until_whitespace(impl_span);
|
||||
impl_span
|
||||
}
|
||||
|
||||
crate fn add_typo_suggestion(
|
||||
err: &mut DiagnosticBuilder<'_>, suggestion: Option<TypoSuggestion>, span: Span
|
||||
) -> bool {
|
||||
if let Some(suggestion) = suggestion {
|
||||
@@ -65,7 +73,7 @@ fn add_typo_suggestion(
|
||||
false
|
||||
}
|
||||
|
||||
fn add_module_candidates(
|
||||
crate fn add_module_candidates(
|
||||
module: Module<'_>, names: &mut Vec<TypoSuggestion>, filter_fn: &impl Fn(Res) -> bool
|
||||
) {
|
||||
for (&(ident, _), resolution) in module.resolutions.borrow().iter() {
|
||||
@@ -79,479 +87,267 @@ fn add_module_candidates(
|
||||
}
|
||||
|
||||
impl<'a> Resolver<'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 }
|
||||
};
|
||||
/// Combines an error with provided span and emits it.
|
||||
///
|
||||
/// This takes the error provided, combines it with the span and any additional spans inside the
|
||||
/// error and emits it.
|
||||
crate fn report_error(&self, span: Span, resolution_error: ResolutionError<'_>) {
|
||||
self.into_struct_error(span, resolution_error).emit();
|
||||
}
|
||||
|
||||
// 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_without_parent_scope(
|
||||
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.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.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.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(
|
||||
crate fn into_struct_error(
|
||||
&self, span: Span, resolution_error: ResolutionError<'_>
|
||||
) -> DiagnosticBuilder<'_> {
|
||||
match resolution_error {
|
||||
ResolutionError::GenericParamsFromOuterFunction(outer_res) => {
|
||||
let mut err = struct_span_err!(self.session,
|
||||
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,
|
||||
E0401,
|
||||
"can't use generic parameters from outer function",
|
||||
);
|
||||
}
|
||||
}
|
||||
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, format!("use of generic parameter from outer function"));
|
||||
|
||||
let cm = self.session.source_map();
|
||||
match outer_res {
|
||||
Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
|
||||
if let Some(impl_span) = maybe_impl_defid.and_then(|def_id| {
|
||||
self.definitions.opt_span(def_id)
|
||||
}) {
|
||||
err.span_label(
|
||||
span,
|
||||
"a field by this name exists in `Self`",
|
||||
reduce_impl_span_to_impl_keyword(cm, impl_span),
|
||||
"`Self` type implicitly declared here, by this `impl`",
|
||||
);
|
||||
}
|
||||
}
|
||||
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.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.struct_constructors.get(&def_id).cloned() {
|
||||
let accessible_ctor = self.is_accessible(ctor_vis);
|
||||
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.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.field_names.get(&did) {
|
||||
if field_names.iter().any(|&field_name| ident.name == field_name) {
|
||||
return Some(AssocSuggestion::Field);
|
||||
}
|
||||
match (maybe_trait_defid, maybe_impl_defid) {
|
||||
(Some(_), None) => {
|
||||
err.span_label(span, "can't use `Self` here");
|
||||
}
|
||||
(_, Some(_)) => {
|
||||
err.span_label(span, "use a type here instead");
|
||||
}
|
||||
(None, None) => bug!("`impl` without trait nor type?"),
|
||||
}
|
||||
_ => {}
|
||||
return err;
|
||||
},
|
||||
Res::Def(DefKind::TyParam, def_id) => {
|
||||
if let Some(span) = self.definitions.opt_span(def_id) {
|
||||
err.span_label(span, "type parameter from outer function");
|
||||
}
|
||||
}
|
||||
Res::Def(DefKind::ConstParam, def_id) => {
|
||||
if let Some(span) = self.definitions.opt_span(def_id) {
|
||||
err.span_label(span, "const parameter from outer function");
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
bug!("GenericParamsFromOuterFunction should only be used with Res::SelfTy, \
|
||||
DefKind::TyParam");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.resolve_ident_in_module(
|
||||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
ns,
|
||||
None,
|
||||
false,
|
||||
module.span,
|
||||
) {
|
||||
let res = binding.res();
|
||||
if filter_fn(res) {
|
||||
return Some(if self.has_self.contains(&res.def_id()) {
|
||||
AssocSuggestion::MethodWithSelf
|
||||
} else {
|
||||
AssocSuggestion::AssocItem
|
||||
});
|
||||
// Try to retrieve the span of the function signature and generate a new message
|
||||
// with a local type or const parameter.
|
||||
let sugg_msg = &format!("try using a local generic parameter instead");
|
||||
if let Some((sugg_span, new_snippet)) = cm.generate_local_type_param_snippet(span) {
|
||||
// Suggest the modification to the user
|
||||
err.span_suggestion(
|
||||
sugg_span,
|
||||
sugg_msg,
|
||||
new_snippet,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if let Some(sp) = cm.generate_fn_name_span(span) {
|
||||
err.span_label(sp,
|
||||
format!("try adding a local generic parameter in this method instead"));
|
||||
} else {
|
||||
err.help(&format!("try using a local generic parameter instead"));
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => {
|
||||
let mut err = struct_span_err!(self.session,
|
||||
span,
|
||||
E0403,
|
||||
"the name `{}` is already used for a generic \
|
||||
parameter in this list of generic parameters",
|
||||
name);
|
||||
err.span_label(span, "already used");
|
||||
err.span_label(first_use_span, format!("first use of `{}`", name));
|
||||
err
|
||||
}
|
||||
ResolutionError::MethodNotMemberOfTrait(method, trait_) => {
|
||||
let mut err = struct_span_err!(self.session,
|
||||
span,
|
||||
E0407,
|
||||
"method `{}` is not a member of trait `{}`",
|
||||
method,
|
||||
trait_);
|
||||
err.span_label(span, format!("not a member of trait `{}`", trait_));
|
||||
err
|
||||
}
|
||||
ResolutionError::TypeNotMemberOfTrait(type_, trait_) => {
|
||||
let mut err = struct_span_err!(self.session,
|
||||
span,
|
||||
E0437,
|
||||
"type `{}` is not a member of trait `{}`",
|
||||
type_,
|
||||
trait_);
|
||||
err.span_label(span, format!("not a member of trait `{}`", trait_));
|
||||
err
|
||||
}
|
||||
ResolutionError::ConstNotMemberOfTrait(const_, trait_) => {
|
||||
let mut err = struct_span_err!(self.session,
|
||||
span,
|
||||
E0438,
|
||||
"const `{}` is not a member of trait `{}`",
|
||||
const_,
|
||||
trait_);
|
||||
err.span_label(span, format!("not a member of trait `{}`", trait_));
|
||||
err
|
||||
}
|
||||
ResolutionError::VariableNotBoundInPattern(binding_error) => {
|
||||
let target_sp = binding_error.target.iter().cloned().collect::<Vec<_>>();
|
||||
let msp = MultiSpan::from_spans(target_sp.clone());
|
||||
let msg = format!("variable `{}` is not bound in all patterns", binding_error.name);
|
||||
let mut err = self.session.struct_span_err_with_code(
|
||||
msp,
|
||||
&msg,
|
||||
DiagnosticId::Error("E0408".into()),
|
||||
);
|
||||
for sp in target_sp {
|
||||
err.span_label(sp, format!("pattern doesn't bind `{}`", binding_error.name));
|
||||
}
|
||||
let origin_sp = binding_error.origin.iter().cloned();
|
||||
for sp in origin_sp {
|
||||
err.span_label(sp, "variable not in all patterns");
|
||||
}
|
||||
err
|
||||
}
|
||||
ResolutionError::VariableBoundWithDifferentMode(variable_name,
|
||||
first_binding_span) => {
|
||||
let mut err = struct_span_err!(self.session,
|
||||
span,
|
||||
E0409,
|
||||
"variable `{}` is bound in inconsistent \
|
||||
ways within the same match arm",
|
||||
variable_name);
|
||||
err.span_label(span, "bound in different ways");
|
||||
err.span_label(first_binding_span, "first binding");
|
||||
err
|
||||
}
|
||||
ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => {
|
||||
let mut err = struct_span_err!(self.session,
|
||||
span,
|
||||
E0415,
|
||||
"identifier `{}` is bound more than once in this parameter list",
|
||||
identifier);
|
||||
err.span_label(span, "used as parameter more than once");
|
||||
err
|
||||
}
|
||||
ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => {
|
||||
let mut err = struct_span_err!(self.session,
|
||||
span,
|
||||
E0416,
|
||||
"identifier `{}` is bound more than once in the same pattern",
|
||||
identifier);
|
||||
err.span_label(span, "used in a pattern more than once");
|
||||
err
|
||||
}
|
||||
ResolutionError::UndeclaredLabel(name, lev_candidate) => {
|
||||
let mut err = struct_span_err!(self.session,
|
||||
span,
|
||||
E0426,
|
||||
"use of undeclared label `{}`",
|
||||
name);
|
||||
if let Some(lev_candidate) = lev_candidate {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"a label with a similar name exists in this scope",
|
||||
lev_candidate.to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.span_label(span, format!("undeclared label `{}`", name));
|
||||
}
|
||||
err
|
||||
}
|
||||
ResolutionError::SelfImportsOnlyAllowedWithin => {
|
||||
struct_span_err!(self.session,
|
||||
span,
|
||||
E0429,
|
||||
"{}",
|
||||
"`self` imports are only allowed within a { } list")
|
||||
}
|
||||
ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
|
||||
let mut err = struct_span_err!(self.session, span, E0430,
|
||||
"`self` import can only appear once in an import list");
|
||||
err.span_label(span, "can only appear once in an import list");
|
||||
err
|
||||
}
|
||||
ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
|
||||
let mut err = struct_span_err!(self.session, span, E0431,
|
||||
"`self` import can only appear in an import list with \
|
||||
a non-empty prefix");
|
||||
err.span_label(span, "can only appear in an import list with a non-empty prefix");
|
||||
err
|
||||
}
|
||||
ResolutionError::FailedToResolve { label, suggestion } => {
|
||||
let mut err = struct_span_err!(self.session, span, E0433,
|
||||
"failed to resolve: {}", &label);
|
||||
err.span_label(span, label);
|
||||
|
||||
if let Some((suggestions, msg, applicability)) = suggestion {
|
||||
err.multipart_suggestion(&msg, suggestions, applicability);
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
|
||||
let mut err = struct_span_err!(self.session,
|
||||
span,
|
||||
E0434,
|
||||
"{}",
|
||||
"can't capture dynamic environment in a fn item");
|
||||
err.help("use the `|| { ... }` closure form instead");
|
||||
err
|
||||
}
|
||||
ResolutionError::AttemptToUseNonConstantValueInConstant => {
|
||||
let mut err = struct_span_err!(self.session, span, E0435,
|
||||
"attempt to use a non-constant value in a constant");
|
||||
err.span_label(span, "non-constant value");
|
||||
err
|
||||
}
|
||||
ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => {
|
||||
let shadows_what = binding.descr();
|
||||
let mut err = struct_span_err!(self.session, span, E0530, "{}s cannot shadow {}s",
|
||||
what_binding, shadows_what);
|
||||
err.span_label(span, format!("cannot be named the same as {} {}",
|
||||
binding.article(), shadows_what));
|
||||
let participle = if binding.is_import() { "imported" } else { "defined" };
|
||||
let msg = format!("the {} `{}` is {} here", shadows_what, name, participle);
|
||||
err.span_label(binding.span, msg);
|
||||
err
|
||||
}
|
||||
ResolutionError::ForwardDeclaredTyParam => {
|
||||
let mut err = struct_span_err!(self.session, span, E0128,
|
||||
"type parameters with a default cannot use \
|
||||
forward declared identifiers");
|
||||
err.span_label(
|
||||
span, "defaulted type parameters cannot be forward declared".to_string());
|
||||
err
|
||||
}
|
||||
ResolutionError::ConstParamDependentOnTypeParam => {
|
||||
let mut err = struct_span_err!(
|
||||
self.session,
|
||||
span,
|
||||
E0671,
|
||||
"const parameters cannot depend on type parameters"
|
||||
);
|
||||
err.span_label(span, format!("const parameter depends on type parameter"));
|
||||
err
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Lookup typo candidate in scope for a macro or import.
|
||||
@@ -569,9 +365,10 @@ fn early_lookup_typo_candidate(
|
||||
let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
|
||||
if filter_fn(res) {
|
||||
for derive in &parent_scope.derives {
|
||||
let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
|
||||
let parent_scope =
|
||||
&ParentScope { derives: Vec::new(), ..*parent_scope };
|
||||
if let Ok((Some(ext), _)) = this.resolve_macro_path(
|
||||
derive, Some(MacroKind::Derive), &parent_scope, false, false
|
||||
derive, Some(MacroKind::Derive), parent_scope, false, false
|
||||
) {
|
||||
suggestions.extend(ext.helper_attrs.iter().map(|name| {
|
||||
TypoSuggestion::from_res(*name, res)
|
||||
@@ -683,98 +480,6 @@ fn early_lookup_typo_candidate(
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
names.extend(self.extern_prelude.clone().iter().flat_map(|(ident, _)| {
|
||||
self.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.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.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_without_parent_scope(
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_import_candidates_from_module<FilterFn>(&mut self,
|
||||
lookup_ident: Ident,
|
||||
namespace: Namespace,
|
||||
@@ -901,65 +606,6 @@ fn lookup_import_candidates_from_module<FilterFn>(&mut self,
|
||||
suggestions
|
||||
}
|
||||
|
||||
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.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.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.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
|
||||
})
|
||||
}
|
||||
|
||||
crate fn unresolved_macro_suggestions(
|
||||
&mut self,
|
||||
err: &mut DiagnosticBuilder<'a>,
|
||||
@@ -969,7 +615,7 @@ fn collect_enum_variants(&mut self, def_id: DefId) -> Option<Vec<Path>> {
|
||||
) {
|
||||
let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind);
|
||||
let suggestion = self.early_lookup_typo_candidate(
|
||||
ScopeSet::Macro(macro_kind), &parent_scope, ident, is_expected
|
||||
ScopeSet::Macro(macro_kind), parent_scope, ident, is_expected
|
||||
);
|
||||
add_typo_suggestion(err, suggestion, ident.span);
|
||||
|
||||
@@ -1029,7 +675,7 @@ fn make_missing_self_suggestion(
|
||||
) -> Option<(Vec<Segment>, Vec<String>)> {
|
||||
// Replace first ident with `self` and check if that is valid.
|
||||
path[0].ident.name = kw::SelfLower;
|
||||
let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
|
||||
let result = self.r.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
|
||||
debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
|
||||
if let PathResult::Module(..) = result {
|
||||
Some((path, Vec::new()))
|
||||
@@ -1053,7 +699,7 @@ fn make_missing_crate_suggestion(
|
||||
) -> Option<(Vec<Segment>, Vec<String>)> {
|
||||
// Replace first ident with `crate` and check if that is valid.
|
||||
path[0].ident.name = kw::Crate;
|
||||
let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
|
||||
let result = self.r.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
|
||||
debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result);
|
||||
if let PathResult::Module(..) = result {
|
||||
Some((
|
||||
@@ -1084,7 +730,7 @@ fn make_missing_super_suggestion(
|
||||
) -> Option<(Vec<Segment>, Vec<String>)> {
|
||||
// Replace first ident with `crate` and check if that is valid.
|
||||
path[0].ident.name = kw::Super;
|
||||
let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
|
||||
let result = self.r.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
|
||||
debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result);
|
||||
if let PathResult::Module(..) = result {
|
||||
Some((path, Vec::new()))
|
||||
@@ -1117,13 +763,13 @@ fn make_external_crate_suggestion(
|
||||
// 1) some consistent ordering for emitted dignostics, and
|
||||
// 2) `std` suggestions before `core` suggestions.
|
||||
let mut extern_crate_names =
|
||||
self.resolver.extern_prelude.iter().map(|(ident, _)| ident.name).collect::<Vec<_>>();
|
||||
self.r.extern_prelude.iter().map(|(ident, _)| ident.name).collect::<Vec<_>>();
|
||||
extern_crate_names.sort_by_key(|name| Reverse(name.as_str()));
|
||||
|
||||
for name in extern_crate_names.into_iter() {
|
||||
// Replace first ident with a crate name and check if that is valid.
|
||||
path[0].ident.name = name;
|
||||
let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
|
||||
let result = self.r.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
|
||||
debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
|
||||
name, path, result);
|
||||
if let PathResult::Module(..) = result {
|
||||
@@ -1189,7 +835,7 @@ pub(crate) fn check_for_module_export_macro(
|
||||
// ie. `use a::b::{c, d, e};`
|
||||
// ^^^
|
||||
let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding(
|
||||
self.resolver.session, directive.span, directive.use_span,
|
||||
self.r.session, directive.span, directive.use_span,
|
||||
);
|
||||
debug!("check_for_module_export_macro: found_closing_brace={:?} binding_span={:?}",
|
||||
found_closing_brace, binding_span);
|
||||
@@ -1204,7 +850,7 @@ pub(crate) fn check_for_module_export_macro(
|
||||
// ie. `use a::b::{c, d};`
|
||||
// ^^^
|
||||
if let Some(previous_span) = extend_span_to_previous_binding(
|
||||
self.resolver.session, binding_span,
|
||||
self.r.session, binding_span,
|
||||
) {
|
||||
debug!("check_for_module_export_macro: previous_span={:?}", previous_span);
|
||||
removal_span = removal_span.with_lo(previous_span.lo());
|
||||
@@ -1222,12 +868,12 @@ pub(crate) fn check_for_module_export_macro(
|
||||
// or `use a::{b, c, d}};`
|
||||
// ^^^^^^^^^^^
|
||||
let (has_nested, after_crate_name) = find_span_immediately_after_crate_name(
|
||||
self.resolver.session, module_name, directive.use_span,
|
||||
self.r.session, module_name, directive.use_span,
|
||||
);
|
||||
debug!("check_for_module_export_macro: has_nested={:?} after_crate_name={:?}",
|
||||
has_nested, after_crate_name);
|
||||
|
||||
let source_map = self.resolver.session.source_map();
|
||||
let source_map = self.r.session.source_map();
|
||||
|
||||
// Add the import to the start, with a `{` if required.
|
||||
let start_point = source_map.start_point(after_crate_name);
|
||||
@@ -1415,21 +1061,6 @@ fn find_span_immediately_after_crate_name(
|
||||
(next_left_bracket == after_second_colon, from_second_colon)
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
|
||||
/// When an entity with a given name is not available in scope, we search for
|
||||
/// entities with that name in all crates. This method allows outputting the
|
||||
/// results of this search in a programmer-friendly way
|
||||
|
||||
@@ -0,0 +1,2004 @@
|
||||
use GenericParameters::*;
|
||||
use RibKind::*;
|
||||
|
||||
use crate::{path_names_to_string, BindingError, CrateLint, LexicalScopeBinding};
|
||||
use crate::{Module, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult};
|
||||
use crate::{ResolutionError, Resolver, Segment, UseError};
|
||||
|
||||
use log::debug;
|
||||
use rustc::{bug, lint, span_bug};
|
||||
use rustc::hir::def::{self, PartialRes, DefKind, CtorKind, PerNS};
|
||||
use rustc::hir::def::Namespace::{self, *};
|
||||
use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
|
||||
use rustc::hir::TraitCandidate;
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use syntax::{unwrap_or, walk_list};
|
||||
use syntax::ast::*;
|
||||
use syntax::ptr::P;
|
||||
use syntax::symbol::{kw, sym};
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
use syntax::visit::{self, Visitor, FnKind};
|
||||
use syntax_pos::Span;
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::mem::replace;
|
||||
|
||||
mod diagnostics;
|
||||
|
||||
type Res = def::Res<NodeId>;
|
||||
|
||||
/// Map from the name in a pattern to its binding mode.
|
||||
type BindingMap = FxHashMap<Ident, BindingInfo>;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct BindingInfo {
|
||||
span: Span,
|
||||
binding_mode: BindingMode,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum GenericParameters<'a, 'b> {
|
||||
NoGenericParams,
|
||||
HasGenericParams(// Type parameters.
|
||||
&'b Generics,
|
||||
|
||||
// The kind of the rib used for type parameters.
|
||||
RibKind<'a>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
enum PatternSource {
|
||||
Match,
|
||||
Let,
|
||||
For,
|
||||
FnParam,
|
||||
}
|
||||
|
||||
impl PatternSource {
|
||||
fn descr(self) -> &'static str {
|
||||
match self {
|
||||
PatternSource::Match => "match binding",
|
||||
PatternSource::Let => "let binding",
|
||||
PatternSource::For => "for binding",
|
||||
PatternSource::FnParam => "function parameter",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The rib kind restricts certain accesses,
|
||||
/// e.g. to a `Res::Local` of an outer item.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
crate enum RibKind<'a> {
|
||||
/// No restriction needs to be applied.
|
||||
NormalRibKind,
|
||||
|
||||
/// We passed through an impl or trait and are now in one of its
|
||||
/// methods or associated types. Allow references to ty params that impl or trait
|
||||
/// binds. Disallow any other upvars (including other ty params that are
|
||||
/// upvars).
|
||||
AssocItemRibKind,
|
||||
|
||||
/// We passed through a function definition. Disallow upvars.
|
||||
/// Permit only those const parameters that are specified in the function's generics.
|
||||
FnItemRibKind,
|
||||
|
||||
/// We passed through an item scope. Disallow upvars.
|
||||
ItemRibKind,
|
||||
|
||||
/// We're in a constant item. Can't refer to dynamic stuff.
|
||||
ConstantItemRibKind,
|
||||
|
||||
/// We passed through a module.
|
||||
ModuleRibKind(Module<'a>),
|
||||
|
||||
/// We passed through a `macro_rules!` statement
|
||||
MacroDefinition(DefId),
|
||||
|
||||
/// All bindings in this rib are type parameters that can't be used
|
||||
/// from the default of a type parameter because they're not declared
|
||||
/// before said type parameter. Also see the `visit_generics` override.
|
||||
ForwardTyParamBanRibKind,
|
||||
|
||||
/// We forbid the use of type parameters as the types of const parameters.
|
||||
TyParamAsConstParamTy,
|
||||
}
|
||||
|
||||
/// A single local scope.
|
||||
///
|
||||
/// A rib represents a scope names can live in. Note that these appear in many places, not just
|
||||
/// around braces. At any place where the list of accessible names (of the given namespace)
|
||||
/// changes or a new restrictions on the name accessibility are introduced, a new rib is put onto a
|
||||
/// stack. This may be, for example, a `let` statement (because it introduces variables), a macro,
|
||||
/// etc.
|
||||
///
|
||||
/// Different [rib kinds](enum.RibKind) are transparent for different names.
|
||||
///
|
||||
/// The resolution keeps a separate stack of ribs as it traverses the AST for each namespace. When
|
||||
/// resolving, the name is looked up from inside out.
|
||||
#[derive(Debug)]
|
||||
crate struct Rib<'a, R = Res> {
|
||||
pub bindings: FxHashMap<Ident, R>,
|
||||
pub kind: RibKind<'a>,
|
||||
}
|
||||
|
||||
impl<'a, R> Rib<'a, R> {
|
||||
fn new(kind: RibKind<'a>) -> Rib<'a, R> {
|
||||
Rib {
|
||||
bindings: Default::default(),
|
||||
kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
crate enum AliasPossibility {
|
||||
No,
|
||||
Maybe,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
crate enum PathSource<'a> {
|
||||
// Type paths `Path`.
|
||||
Type,
|
||||
// Trait paths in bounds or impls.
|
||||
Trait(AliasPossibility),
|
||||
// Expression paths `path`, with optional parent context.
|
||||
Expr(Option<&'a Expr>),
|
||||
// Paths in path patterns `Path`.
|
||||
Pat,
|
||||
// Paths in struct expressions and patterns `Path { .. }`.
|
||||
Struct,
|
||||
// Paths in tuple struct patterns `Path(..)`.
|
||||
TupleStruct,
|
||||
// `m::A::B` in `<T as m::A>::B::C`.
|
||||
TraitItem(Namespace),
|
||||
}
|
||||
|
||||
impl<'a> PathSource<'a> {
|
||||
fn namespace(self) -> Namespace {
|
||||
match self {
|
||||
PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS,
|
||||
PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS,
|
||||
PathSource::TraitItem(ns) => ns,
|
||||
}
|
||||
}
|
||||
|
||||
fn defer_to_typeck(self) -> bool {
|
||||
match self {
|
||||
PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
|
||||
PathSource::Struct | PathSource::TupleStruct => true,
|
||||
PathSource::Trait(_) | PathSource::TraitItem(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn descr_expected(self) -> &'static str {
|
||||
match self {
|
||||
PathSource::Type => "type",
|
||||
PathSource::Trait(_) => "trait",
|
||||
PathSource::Pat => "unit struct/variant or constant",
|
||||
PathSource::Struct => "struct, variant or union type",
|
||||
PathSource::TupleStruct => "tuple struct/variant",
|
||||
PathSource::TraitItem(ns) => match ns {
|
||||
TypeNS => "associated type",
|
||||
ValueNS => "method or associated constant",
|
||||
MacroNS => bug!("associated macro"),
|
||||
},
|
||||
PathSource::Expr(parent) => match parent.map(|p| &p.node) {
|
||||
// "function" here means "anything callable" rather than `DefKind::Fn`,
|
||||
// this is not precise but usually more helpful than just "value".
|
||||
Some(&ExprKind::Call(..)) => "function",
|
||||
_ => "value",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
crate fn is_expected(self, res: Res) -> bool {
|
||||
match self {
|
||||
PathSource::Type => match res {
|
||||
Res::Def(DefKind::Struct, _)
|
||||
| Res::Def(DefKind::Union, _)
|
||||
| Res::Def(DefKind::Enum, _)
|
||||
| Res::Def(DefKind::Trait, _)
|
||||
| Res::Def(DefKind::TraitAlias, _)
|
||||
| Res::Def(DefKind::TyAlias, _)
|
||||
| Res::Def(DefKind::AssocTy, _)
|
||||
| Res::PrimTy(..)
|
||||
| Res::Def(DefKind::TyParam, _)
|
||||
| Res::SelfTy(..)
|
||||
| Res::Def(DefKind::OpaqueTy, _)
|
||||
| Res::Def(DefKind::ForeignTy, _) => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::Trait(AliasPossibility::No) => match res {
|
||||
Res::Def(DefKind::Trait, _) => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::Trait(AliasPossibility::Maybe) => match res {
|
||||
Res::Def(DefKind::Trait, _) => true,
|
||||
Res::Def(DefKind::TraitAlias, _) => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::Expr(..) => match res {
|
||||
Res::Def(DefKind::Ctor(_, CtorKind::Const), _)
|
||||
| Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
|
||||
| Res::Def(DefKind::Const, _)
|
||||
| Res::Def(DefKind::Static, _)
|
||||
| Res::Local(..)
|
||||
| Res::Def(DefKind::Fn, _)
|
||||
| Res::Def(DefKind::Method, _)
|
||||
| Res::Def(DefKind::AssocConst, _)
|
||||
| Res::SelfCtor(..)
|
||||
| Res::Def(DefKind::ConstParam, _) => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::Pat => match res {
|
||||
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) |
|
||||
Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) |
|
||||
Res::SelfCtor(..) => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::TupleStruct => match res {
|
||||
Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::Struct => match res {
|
||||
Res::Def(DefKind::Struct, _)
|
||||
| Res::Def(DefKind::Union, _)
|
||||
| Res::Def(DefKind::Variant, _)
|
||||
| Res::Def(DefKind::TyAlias, _)
|
||||
| Res::Def(DefKind::AssocTy, _)
|
||||
| Res::SelfTy(..) => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::TraitItem(ns) => match res {
|
||||
Res::Def(DefKind::AssocConst, _)
|
||||
| Res::Def(DefKind::Method, _) if ns == ValueNS => true,
|
||||
Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true,
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn error_code(self, has_unexpected_resolution: bool) -> &'static str {
|
||||
__diagnostic_used!(E0404);
|
||||
__diagnostic_used!(E0405);
|
||||
__diagnostic_used!(E0412);
|
||||
__diagnostic_used!(E0422);
|
||||
__diagnostic_used!(E0423);
|
||||
__diagnostic_used!(E0425);
|
||||
__diagnostic_used!(E0531);
|
||||
__diagnostic_used!(E0532);
|
||||
__diagnostic_used!(E0573);
|
||||
__diagnostic_used!(E0574);
|
||||
__diagnostic_used!(E0575);
|
||||
__diagnostic_used!(E0576);
|
||||
match (self, has_unexpected_resolution) {
|
||||
(PathSource::Trait(_), true) => "E0404",
|
||||
(PathSource::Trait(_), false) => "E0405",
|
||||
(PathSource::Type, true) => "E0573",
|
||||
(PathSource::Type, false) => "E0412",
|
||||
(PathSource::Struct, true) => "E0574",
|
||||
(PathSource::Struct, false) => "E0422",
|
||||
(PathSource::Expr(..), true) => "E0423",
|
||||
(PathSource::Expr(..), false) => "E0425",
|
||||
(PathSource::Pat, true) | (PathSource::TupleStruct, true) => "E0532",
|
||||
(PathSource::Pat, false) | (PathSource::TupleStruct, false) => "E0531",
|
||||
(PathSource::TraitItem(..), true) => "E0575",
|
||||
(PathSource::TraitItem(..), false) => "E0576",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LateResolutionVisitor<'a, 'b> {
|
||||
r: &'b mut Resolver<'a>,
|
||||
|
||||
/// The module that represents the current item scope.
|
||||
parent_scope: ParentScope<'a>,
|
||||
|
||||
/// The current set of local scopes for types and values.
|
||||
/// FIXME #4948: Reuse ribs to avoid allocation.
|
||||
ribs: PerNS<Vec<Rib<'a>>>,
|
||||
|
||||
/// The current set of local scopes, for labels.
|
||||
label_ribs: Vec<Rib<'a, NodeId>>,
|
||||
|
||||
/// The trait that the current context can refer to.
|
||||
current_trait_ref: Option<(Module<'a>, TraitRef)>,
|
||||
|
||||
/// The current trait's associated types' ident, used for diagnostic suggestions.
|
||||
current_trait_assoc_types: Vec<Ident>,
|
||||
|
||||
/// The current self type if inside an impl (used for better errors).
|
||||
current_self_type: Option<Ty>,
|
||||
|
||||
/// The current self item if inside an ADT (used for better errors).
|
||||
current_self_item: Option<NodeId>,
|
||||
|
||||
/// A list of labels as of yet unused. Labels will be removed from this map when
|
||||
/// they are used (in a `break` or `continue` statement)
|
||||
unused_labels: FxHashMap<NodeId, Span>,
|
||||
|
||||
/// Only used for better errors on `fn(): fn()`.
|
||||
current_type_ascription: Vec<Span>,
|
||||
}
|
||||
|
||||
/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
|
||||
impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
|
||||
fn visit_item(&mut self, item: &'tcx Item) {
|
||||
self.resolve_item(item);
|
||||
}
|
||||
fn visit_arm(&mut self, arm: &'tcx Arm) {
|
||||
self.resolve_arm(arm);
|
||||
}
|
||||
fn visit_block(&mut self, block: &'tcx Block) {
|
||||
self.resolve_block(block);
|
||||
}
|
||||
fn visit_anon_const(&mut self, constant: &'tcx AnonConst) {
|
||||
debug!("visit_anon_const {:?}", constant);
|
||||
self.with_constant_rib(|this| {
|
||||
visit::walk_anon_const(this, constant);
|
||||
});
|
||||
}
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr) {
|
||||
self.resolve_expr(expr, None);
|
||||
}
|
||||
fn visit_local(&mut self, local: &'tcx Local) {
|
||||
self.resolve_local(local);
|
||||
}
|
||||
fn visit_ty(&mut self, ty: &'tcx Ty) {
|
||||
match ty.node {
|
||||
TyKind::Path(ref qself, ref path) => {
|
||||
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
|
||||
}
|
||||
TyKind::ImplicitSelf => {
|
||||
let self_ty = Ident::with_empty_ctxt(kw::SelfUpper);
|
||||
let res = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.id), ty.span)
|
||||
.map_or(Res::Err, |d| d.res());
|
||||
self.r.record_partial_res(ty.id, PartialRes::new(res));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
visit::walk_ty(self, ty);
|
||||
}
|
||||
fn visit_poly_trait_ref(&mut self,
|
||||
tref: &'tcx PolyTraitRef,
|
||||
m: &'tcx TraitBoundModifier) {
|
||||
self.smart_resolve_path(tref.trait_ref.ref_id, None,
|
||||
&tref.trait_ref.path, PathSource::Trait(AliasPossibility::Maybe));
|
||||
visit::walk_poly_trait_ref(self, tref, m);
|
||||
}
|
||||
fn visit_foreign_item(&mut self, foreign_item: &'tcx ForeignItem) {
|
||||
let generic_params = match foreign_item.node {
|
||||
ForeignItemKind::Fn(_, ref generics) => {
|
||||
HasGenericParams(generics, ItemRibKind)
|
||||
}
|
||||
ForeignItemKind::Static(..) => NoGenericParams,
|
||||
ForeignItemKind::Ty => NoGenericParams,
|
||||
ForeignItemKind::Macro(..) => NoGenericParams,
|
||||
};
|
||||
self.with_generic_param_rib(generic_params, |this| {
|
||||
visit::walk_foreign_item(this, foreign_item);
|
||||
});
|
||||
}
|
||||
fn visit_fn(&mut self,
|
||||
function_kind: FnKind<'tcx>,
|
||||
declaration: &'tcx FnDecl,
|
||||
_: Span,
|
||||
_: NodeId)
|
||||
{
|
||||
debug!("(resolving function) entering function");
|
||||
let rib_kind = match function_kind {
|
||||
FnKind::ItemFn(..) => FnItemRibKind,
|
||||
FnKind::Method(..) | FnKind::Closure(_) => NormalRibKind,
|
||||
};
|
||||
|
||||
// Create a value rib for the function.
|
||||
self.ribs[ValueNS].push(Rib::new(rib_kind));
|
||||
|
||||
// Create a label rib for the function.
|
||||
self.label_ribs.push(Rib::new(rib_kind));
|
||||
|
||||
// Add each argument to the rib.
|
||||
let mut bindings_list = FxHashMap::default();
|
||||
for argument in &declaration.inputs {
|
||||
self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
|
||||
|
||||
self.visit_ty(&argument.ty);
|
||||
|
||||
debug!("(resolving function) recorded argument");
|
||||
}
|
||||
visit::walk_fn_ret_ty(self, &declaration.output);
|
||||
|
||||
// Resolve the function body, potentially inside the body of an async closure
|
||||
match function_kind {
|
||||
FnKind::ItemFn(.., body) |
|
||||
FnKind::Method(.., body) => {
|
||||
self.visit_block(body);
|
||||
}
|
||||
FnKind::Closure(body) => {
|
||||
self.visit_expr(body);
|
||||
}
|
||||
};
|
||||
|
||||
debug!("(resolving function) leaving function");
|
||||
|
||||
self.label_ribs.pop();
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
|
||||
fn visit_generics(&mut self, generics: &'tcx Generics) {
|
||||
// For type parameter defaults, we have to ban access
|
||||
// to following type parameters, as the InternalSubsts can only
|
||||
// provide previous type parameters as they're built. We
|
||||
// put all the parameters on the ban list and then remove
|
||||
// them one by one as they are processed and become available.
|
||||
let mut default_ban_rib = Rib::new(ForwardTyParamBanRibKind);
|
||||
let mut found_default = false;
|
||||
default_ban_rib.bindings.extend(generics.params.iter()
|
||||
.filter_map(|param| match param.kind {
|
||||
GenericParamKind::Const { .. } |
|
||||
GenericParamKind::Lifetime { .. } => None,
|
||||
GenericParamKind::Type { ref default, .. } => {
|
||||
found_default |= default.is_some();
|
||||
if found_default {
|
||||
Some((Ident::with_empty_ctxt(param.ident.name), Res::Err))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
// We also ban access to type parameters for use as the types of const parameters.
|
||||
let mut const_ty_param_ban_rib = Rib::new(TyParamAsConstParamTy);
|
||||
const_ty_param_ban_rib.bindings.extend(generics.params.iter()
|
||||
.filter(|param| {
|
||||
if let GenericParamKind::Type { .. } = param.kind {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.map(|param| (Ident::with_empty_ctxt(param.ident.name), Res::Err)));
|
||||
|
||||
for param in &generics.params {
|
||||
match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => self.visit_generic_param(param),
|
||||
GenericParamKind::Type { ref default, .. } => {
|
||||
for bound in ¶m.bounds {
|
||||
self.visit_param_bound(bound);
|
||||
}
|
||||
|
||||
if let Some(ref ty) = default {
|
||||
self.ribs[TypeNS].push(default_ban_rib);
|
||||
self.visit_ty(ty);
|
||||
default_ban_rib = self.ribs[TypeNS].pop().unwrap();
|
||||
}
|
||||
|
||||
// Allow all following defaults to refer to this type parameter.
|
||||
default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name));
|
||||
}
|
||||
GenericParamKind::Const { ref ty } => {
|
||||
self.ribs[TypeNS].push(const_ty_param_ban_rib);
|
||||
|
||||
for bound in ¶m.bounds {
|
||||
self.visit_param_bound(bound);
|
||||
}
|
||||
|
||||
self.visit_ty(ty);
|
||||
|
||||
const_ty_param_ban_rib = self.ribs[TypeNS].pop().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
for p in &generics.where_clause.predicates {
|
||||
self.visit_where_predicate(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> LateResolutionVisitor<'a, '_> {
|
||||
fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b> {
|
||||
// During late resolution we only track the module component of the parent scope,
|
||||
// although it may be useful to track other components as well for diagnostics.
|
||||
let parent_scope = resolver.dummy_parent_scope();
|
||||
let graph_root = resolver.graph_root;
|
||||
LateResolutionVisitor {
|
||||
r: resolver,
|
||||
parent_scope,
|
||||
ribs: PerNS {
|
||||
value_ns: vec![Rib::new(ModuleRibKind(graph_root))],
|
||||
type_ns: vec![Rib::new(ModuleRibKind(graph_root))],
|
||||
macro_ns: vec![Rib::new(ModuleRibKind(graph_root))],
|
||||
},
|
||||
label_ribs: Vec::new(),
|
||||
current_trait_ref: None,
|
||||
current_trait_assoc_types: Vec::new(),
|
||||
current_self_type: None,
|
||||
current_self_item: None,
|
||||
unused_labels: Default::default(),
|
||||
current_type_ascription: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_ident_in_lexical_scope(&mut self,
|
||||
ident: Ident,
|
||||
ns: Namespace,
|
||||
record_used_id: Option<NodeId>,
|
||||
path_span: Span)
|
||||
-> Option<LexicalScopeBinding<'a>> {
|
||||
self.r.resolve_ident_in_lexical_scope(
|
||||
ident, ns, &self.parent_scope, record_used_id, path_span, &self.ribs[ns]
|
||||
)
|
||||
}
|
||||
|
||||
fn resolve_path(
|
||||
&mut self,
|
||||
path: &[Segment],
|
||||
opt_ns: Option<Namespace>, // `None` indicates a module path in import
|
||||
record_used: bool,
|
||||
path_span: Span,
|
||||
crate_lint: CrateLint,
|
||||
) -> PathResult<'a> {
|
||||
self.r.resolve_path_with_ribs(
|
||||
path, opt_ns, &self.parent_scope, record_used, path_span, crate_lint, Some(&self.ribs)
|
||||
)
|
||||
}
|
||||
|
||||
// AST resolution
|
||||
//
|
||||
// We maintain a list of value ribs and type ribs.
|
||||
//
|
||||
// Simultaneously, we keep track of the current position in the module
|
||||
// graph in the `parent_scope.module` pointer. When we go to resolve a name in
|
||||
// the value or type namespaces, we first look through all the ribs and
|
||||
// then query the module graph. When we resolve a name in the module
|
||||
// namespace, we can skip all the ribs (since nested modules are not
|
||||
// allowed within blocks in Rust) and jump straight to the current module
|
||||
// graph node.
|
||||
//
|
||||
// Named implementations are handled separately. When we find a method
|
||||
// call, we consult the module node to find all of the implementations in
|
||||
// scope. This information is lazily cached in the module node. We then
|
||||
// generate a fake "implementation scope" containing all the
|
||||
// implementations thus found, for compatibility with old resolve pass.
|
||||
|
||||
fn with_scope<F, T>(&mut self, id: NodeId, f: F) -> T
|
||||
where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T
|
||||
{
|
||||
let id = self.r.definitions.local_def_id(id);
|
||||
let module = self.r.module_map.get(&id).cloned(); // clones a reference
|
||||
if let Some(module) = module {
|
||||
// Move down in the graph.
|
||||
let orig_module = replace(&mut self.parent_scope.module, module);
|
||||
self.ribs[ValueNS].push(Rib::new(ModuleRibKind(module)));
|
||||
self.ribs[TypeNS].push(Rib::new(ModuleRibKind(module)));
|
||||
|
||||
self.r.finalize_current_module_macro_resolutions(module);
|
||||
let ret = f(self);
|
||||
|
||||
self.parent_scope.module = orig_module;
|
||||
self.ribs[ValueNS].pop();
|
||||
self.ribs[TypeNS].pop();
|
||||
ret
|
||||
} else {
|
||||
f(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Searches the current set of local scopes for labels. Returns the first non-`None` label that
|
||||
/// is returned by the given predicate function
|
||||
///
|
||||
/// Stops after meeting a closure.
|
||||
fn search_label<P, R>(&self, mut ident: Ident, pred: P) -> Option<R>
|
||||
where P: Fn(&Rib<'_, NodeId>, Ident) -> Option<R>
|
||||
{
|
||||
for rib in self.label_ribs.iter().rev() {
|
||||
match rib.kind {
|
||||
NormalRibKind => {}
|
||||
// If an invocation of this macro created `ident`, give up on `ident`
|
||||
// and switch to `ident`'s source from the macro definition.
|
||||
MacroDefinition(def) => {
|
||||
if def == self.r.macro_def(ident.span.ctxt()) {
|
||||
ident.span.remove_mark();
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Do not resolve labels across function boundary
|
||||
return None;
|
||||
}
|
||||
}
|
||||
let r = pred(rib, ident);
|
||||
if r.is_some() {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn resolve_adt(&mut self, item: &Item, generics: &Generics) {
|
||||
debug!("resolve_adt");
|
||||
self.with_current_self_item(item, |this| {
|
||||
this.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
|
||||
let item_def_id = this.r.definitions.local_def_id(item.id);
|
||||
this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| {
|
||||
visit::walk_item(this, item);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn future_proof_import(&mut self, use_tree: &UseTree) {
|
||||
let segments = &use_tree.prefix.segments;
|
||||
if !segments.is_empty() {
|
||||
let ident = segments[0].ident;
|
||||
if ident.is_path_segment_keyword() || ident.span.rust_2015() {
|
||||
return;
|
||||
}
|
||||
|
||||
let nss = match use_tree.kind {
|
||||
UseTreeKind::Simple(..) if segments.len() == 1 => &[TypeNS, ValueNS][..],
|
||||
_ => &[TypeNS],
|
||||
};
|
||||
let report_error = |this: &Self, ns| {
|
||||
let what = if ns == TypeNS { "type parameters" } else { "local variables" };
|
||||
this.r.session.span_err(ident.span, &format!("imports cannot refer to {}", what));
|
||||
};
|
||||
|
||||
for &ns in nss {
|
||||
match self.resolve_ident_in_lexical_scope(ident, ns, None, use_tree.prefix.span) {
|
||||
Some(LexicalScopeBinding::Res(..)) => {
|
||||
report_error(self, ns);
|
||||
}
|
||||
Some(LexicalScopeBinding::Item(binding)) => {
|
||||
let orig_blacklisted_binding =
|
||||
replace(&mut self.r.blacklisted_binding, Some(binding));
|
||||
if let Some(LexicalScopeBinding::Res(..)) =
|
||||
self.resolve_ident_in_lexical_scope(ident, ns, None,
|
||||
use_tree.prefix.span) {
|
||||
report_error(self, ns);
|
||||
}
|
||||
self.r.blacklisted_binding = orig_blacklisted_binding;
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
} else if let UseTreeKind::Nested(use_trees) = &use_tree.kind {
|
||||
for (use_tree, _) in use_trees {
|
||||
self.future_proof_import(use_tree);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_item(&mut self, item: &Item) {
|
||||
let name = item.ident.name;
|
||||
debug!("(resolving item) resolving {} ({:?})", name, item.node);
|
||||
|
||||
match item.node {
|
||||
ItemKind::TyAlias(_, ref generics) |
|
||||
ItemKind::OpaqueTy(_, ref generics) |
|
||||
ItemKind::Fn(_, _, ref generics, _) => {
|
||||
self.with_generic_param_rib(
|
||||
HasGenericParams(generics, ItemRibKind),
|
||||
|this| visit::walk_item(this, item)
|
||||
);
|
||||
}
|
||||
|
||||
ItemKind::Enum(_, ref generics) |
|
||||
ItemKind::Struct(_, ref generics) |
|
||||
ItemKind::Union(_, ref generics) => {
|
||||
self.resolve_adt(item, generics);
|
||||
}
|
||||
|
||||
ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
|
||||
self.resolve_implementation(generics,
|
||||
opt_trait_ref,
|
||||
&self_type,
|
||||
item.id,
|
||||
impl_items),
|
||||
|
||||
ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => {
|
||||
// Create a new rib for the trait-wide type parameters.
|
||||
self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
|
||||
let local_def_id = this.r.definitions.local_def_id(item.id);
|
||||
this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
|
||||
this.visit_generics(generics);
|
||||
walk_list!(this, visit_param_bound, bounds);
|
||||
|
||||
for trait_item in trait_items {
|
||||
this.with_trait_items(trait_items, |this| {
|
||||
let generic_params = HasGenericParams(
|
||||
&trait_item.generics,
|
||||
AssocItemRibKind,
|
||||
);
|
||||
this.with_generic_param_rib(generic_params, |this| {
|
||||
match trait_item.node {
|
||||
TraitItemKind::Const(ref ty, ref default) => {
|
||||
this.visit_ty(ty);
|
||||
|
||||
// Only impose the restrictions of
|
||||
// ConstRibKind for an actual constant
|
||||
// expression in a provided default.
|
||||
if let Some(ref expr) = *default{
|
||||
this.with_constant_rib(|this| {
|
||||
this.visit_expr(expr);
|
||||
});
|
||||
}
|
||||
}
|
||||
TraitItemKind::Method(_, _) => {
|
||||
visit::walk_trait_item(this, trait_item)
|
||||
}
|
||||
TraitItemKind::Type(..) => {
|
||||
visit::walk_trait_item(this, trait_item)
|
||||
}
|
||||
TraitItemKind::Macro(_) => {
|
||||
panic!("unexpanded macro in resolve!")
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ItemKind::TraitAlias(ref generics, ref bounds) => {
|
||||
// Create a new rib for the trait-wide type parameters.
|
||||
self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
|
||||
let local_def_id = this.r.definitions.local_def_id(item.id);
|
||||
this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
|
||||
this.visit_generics(generics);
|
||||
walk_list!(this, visit_param_bound, bounds);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ItemKind::Mod(_) | ItemKind::ForeignMod(_) => {
|
||||
self.with_scope(item.id, |this| {
|
||||
visit::walk_item(this, item);
|
||||
});
|
||||
}
|
||||
|
||||
ItemKind::Static(ref ty, _, ref expr) |
|
||||
ItemKind::Const(ref ty, ref expr) => {
|
||||
debug!("resolve_item ItemKind::Const");
|
||||
self.with_item_rib(|this| {
|
||||
this.visit_ty(ty);
|
||||
this.with_constant_rib(|this| {
|
||||
this.visit_expr(expr);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ItemKind::Use(ref use_tree) => {
|
||||
self.future_proof_import(use_tree);
|
||||
}
|
||||
|
||||
ItemKind::ExternCrate(..) |
|
||||
ItemKind::MacroDef(..) | ItemKind::GlobalAsm(..) => {
|
||||
// do nothing, these are just around to be encoded
|
||||
}
|
||||
|
||||
ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"),
|
||||
}
|
||||
}
|
||||
|
||||
fn with_generic_param_rib<'c, F>(&'c mut self, generic_params: GenericParameters<'a, 'c>, f: F)
|
||||
where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
|
||||
{
|
||||
debug!("with_generic_param_rib");
|
||||
match generic_params {
|
||||
HasGenericParams(generics, rib_kind) => {
|
||||
let mut function_type_rib = Rib::new(rib_kind);
|
||||
let mut function_value_rib = Rib::new(rib_kind);
|
||||
let mut seen_bindings = FxHashMap::default();
|
||||
for param in &generics.params {
|
||||
match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => {}
|
||||
GenericParamKind::Type { .. } => {
|
||||
let ident = param.ident.modern();
|
||||
debug!("with_generic_param_rib: {}", param.id);
|
||||
|
||||
if seen_bindings.contains_key(&ident) {
|
||||
let span = seen_bindings.get(&ident).unwrap();
|
||||
let err = ResolutionError::NameAlreadyUsedInParameterList(
|
||||
ident.name,
|
||||
*span,
|
||||
);
|
||||
self.r.report_error(param.ident.span, err);
|
||||
}
|
||||
seen_bindings.entry(ident).or_insert(param.ident.span);
|
||||
|
||||
// Plain insert (no renaming).
|
||||
let res = Res::Def(
|
||||
DefKind::TyParam,
|
||||
self.r.definitions.local_def_id(param.id),
|
||||
);
|
||||
function_type_rib.bindings.insert(ident, res);
|
||||
self.r.record_partial_res(param.id, PartialRes::new(res));
|
||||
}
|
||||
GenericParamKind::Const { .. } => {
|
||||
let ident = param.ident.modern();
|
||||
debug!("with_generic_param_rib: {}", param.id);
|
||||
|
||||
if seen_bindings.contains_key(&ident) {
|
||||
let span = seen_bindings.get(&ident).unwrap();
|
||||
let err = ResolutionError::NameAlreadyUsedInParameterList(
|
||||
ident.name,
|
||||
*span,
|
||||
);
|
||||
self.r.report_error(param.ident.span, err);
|
||||
}
|
||||
seen_bindings.entry(ident).or_insert(param.ident.span);
|
||||
|
||||
let res = Res::Def(
|
||||
DefKind::ConstParam,
|
||||
self.r.definitions.local_def_id(param.id),
|
||||
);
|
||||
function_value_rib.bindings.insert(ident, res);
|
||||
self.r.record_partial_res(param.id, PartialRes::new(res));
|
||||
}
|
||||
}
|
||||
}
|
||||
self.ribs[ValueNS].push(function_value_rib);
|
||||
self.ribs[TypeNS].push(function_type_rib);
|
||||
}
|
||||
|
||||
NoGenericParams => {
|
||||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
|
||||
f(self);
|
||||
|
||||
if let HasGenericParams(..) = generic_params {
|
||||
self.ribs[TypeNS].pop();
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
}
|
||||
|
||||
fn with_label_rib<F>(&mut self, f: F)
|
||||
where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
|
||||
{
|
||||
self.label_ribs.push(Rib::new(NormalRibKind));
|
||||
f(self);
|
||||
self.label_ribs.pop();
|
||||
}
|
||||
|
||||
fn with_item_rib<F>(&mut self, f: F)
|
||||
where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
|
||||
{
|
||||
self.ribs[ValueNS].push(Rib::new(ItemRibKind));
|
||||
self.ribs[TypeNS].push(Rib::new(ItemRibKind));
|
||||
f(self);
|
||||
self.ribs[TypeNS].pop();
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
|
||||
fn with_constant_rib<F>(&mut self, f: F)
|
||||
where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
|
||||
{
|
||||
debug!("with_constant_rib");
|
||||
self.ribs[ValueNS].push(Rib::new(ConstantItemRibKind));
|
||||
self.label_ribs.push(Rib::new(ConstantItemRibKind));
|
||||
f(self);
|
||||
self.label_ribs.pop();
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
|
||||
fn with_current_self_type<T, F>(&mut self, self_type: &Ty, f: F) -> T
|
||||
where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T
|
||||
{
|
||||
// Handle nested impls (inside fn bodies)
|
||||
let previous_value = replace(&mut self.current_self_type, Some(self_type.clone()));
|
||||
let result = f(self);
|
||||
self.current_self_type = previous_value;
|
||||
result
|
||||
}
|
||||
|
||||
fn with_current_self_item<T, F>(&mut self, self_item: &Item, f: F) -> T
|
||||
where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T
|
||||
{
|
||||
let previous_value = replace(&mut self.current_self_item, Some(self_item.id));
|
||||
let result = f(self);
|
||||
self.current_self_item = previous_value;
|
||||
result
|
||||
}
|
||||
|
||||
/// When evaluating a `trait` use its associated types' idents for suggestionsa in E0412.
|
||||
fn with_trait_items<T, F>(&mut self, trait_items: &Vec<TraitItem>, f: F) -> T
|
||||
where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T
|
||||
{
|
||||
let trait_assoc_types = replace(
|
||||
&mut self.current_trait_assoc_types,
|
||||
trait_items.iter().filter_map(|item| match &item.node {
|
||||
TraitItemKind::Type(bounds, _) if bounds.len() == 0 => Some(item.ident),
|
||||
_ => None,
|
||||
}).collect(),
|
||||
);
|
||||
let result = f(self);
|
||||
self.current_trait_assoc_types = trait_assoc_types;
|
||||
result
|
||||
}
|
||||
|
||||
/// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`).
|
||||
fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T
|
||||
where F: FnOnce(&mut LateResolutionVisitor<'_, '_>, Option<DefId>) -> T
|
||||
{
|
||||
let mut new_val = None;
|
||||
let mut new_id = None;
|
||||
if let Some(trait_ref) = opt_trait_ref {
|
||||
let path: Vec<_> = Segment::from_path(&trait_ref.path);
|
||||
let res = self.smart_resolve_path_fragment(
|
||||
trait_ref.ref_id,
|
||||
None,
|
||||
&path,
|
||||
trait_ref.path.span,
|
||||
PathSource::Trait(AliasPossibility::No),
|
||||
CrateLint::SimplePath(trait_ref.ref_id),
|
||||
).base_res();
|
||||
if res != Res::Err {
|
||||
new_id = Some(res.def_id());
|
||||
let span = trait_ref.path.span;
|
||||
if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
|
||||
self.resolve_path(
|
||||
&path,
|
||||
Some(TypeNS),
|
||||
false,
|
||||
span,
|
||||
CrateLint::SimplePath(trait_ref.ref_id),
|
||||
)
|
||||
{
|
||||
new_val = Some((module, trait_ref.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
let original_trait_ref = replace(&mut self.current_trait_ref, new_val);
|
||||
let result = f(self, new_id);
|
||||
self.current_trait_ref = original_trait_ref;
|
||||
result
|
||||
}
|
||||
|
||||
fn with_self_rib<F>(&mut self, self_res: Res, f: F)
|
||||
where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
|
||||
{
|
||||
let mut self_type_rib = Rib::new(NormalRibKind);
|
||||
|
||||
// Plain insert (no renaming, since types are not currently hygienic)
|
||||
self_type_rib.bindings.insert(Ident::with_empty_ctxt(kw::SelfUpper), self_res);
|
||||
self.ribs[TypeNS].push(self_type_rib);
|
||||
f(self);
|
||||
self.ribs[TypeNS].pop();
|
||||
}
|
||||
|
||||
fn with_self_struct_ctor_rib<F>(&mut self, impl_id: DefId, f: F)
|
||||
where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
|
||||
{
|
||||
let self_res = Res::SelfCtor(impl_id);
|
||||
let mut self_type_rib = Rib::new(NormalRibKind);
|
||||
self_type_rib.bindings.insert(Ident::with_empty_ctxt(kw::SelfUpper), self_res);
|
||||
self.ribs[ValueNS].push(self_type_rib);
|
||||
f(self);
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
|
||||
fn resolve_implementation(&mut self,
|
||||
generics: &Generics,
|
||||
opt_trait_reference: &Option<TraitRef>,
|
||||
self_type: &Ty,
|
||||
item_id: NodeId,
|
||||
impl_items: &[ImplItem]) {
|
||||
debug!("resolve_implementation");
|
||||
// If applicable, create a rib for the type parameters.
|
||||
self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
|
||||
// Dummy self type for better errors if `Self` is used in the trait path.
|
||||
this.with_self_rib(Res::SelfTy(None, None), |this| {
|
||||
// Resolve the trait reference, if necessary.
|
||||
this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
|
||||
let item_def_id = this.r.definitions.local_def_id(item_id);
|
||||
this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| {
|
||||
if let Some(trait_ref) = opt_trait_reference.as_ref() {
|
||||
// Resolve type arguments in the trait path.
|
||||
visit::walk_trait_ref(this, trait_ref);
|
||||
}
|
||||
// Resolve the self type.
|
||||
this.visit_ty(self_type);
|
||||
// Resolve the generic parameters.
|
||||
this.visit_generics(generics);
|
||||
// Resolve the items within the impl.
|
||||
this.with_current_self_type(self_type, |this| {
|
||||
this.with_self_struct_ctor_rib(item_def_id, |this| {
|
||||
debug!("resolve_implementation with_self_struct_ctor_rib");
|
||||
for impl_item in impl_items {
|
||||
// We also need a new scope for the impl item type parameters.
|
||||
let generic_params = HasGenericParams(&impl_item.generics,
|
||||
AssocItemRibKind);
|
||||
this.with_generic_param_rib(generic_params, |this| {
|
||||
use crate::ResolutionError::*;
|
||||
match impl_item.node {
|
||||
ImplItemKind::Const(..) => {
|
||||
debug!(
|
||||
"resolve_implementation ImplItemKind::Const",
|
||||
);
|
||||
// If this is a trait impl, ensure the const
|
||||
// exists in trait
|
||||
this.check_trait_item(
|
||||
impl_item.ident,
|
||||
ValueNS,
|
||||
impl_item.span,
|
||||
|n, s| ConstNotMemberOfTrait(n, s),
|
||||
);
|
||||
|
||||
this.with_constant_rib(|this| {
|
||||
visit::walk_impl_item(this, impl_item)
|
||||
});
|
||||
}
|
||||
ImplItemKind::Method(..) => {
|
||||
// If this is a trait impl, ensure the method
|
||||
// exists in trait
|
||||
this.check_trait_item(impl_item.ident,
|
||||
ValueNS,
|
||||
impl_item.span,
|
||||
|n, s| MethodNotMemberOfTrait(n, s));
|
||||
|
||||
visit::walk_impl_item(this, impl_item);
|
||||
}
|
||||
ImplItemKind::TyAlias(ref ty) => {
|
||||
// If this is a trait impl, ensure the type
|
||||
// exists in trait
|
||||
this.check_trait_item(impl_item.ident,
|
||||
TypeNS,
|
||||
impl_item.span,
|
||||
|n, s| TypeNotMemberOfTrait(n, s));
|
||||
|
||||
this.visit_ty(ty);
|
||||
}
|
||||
ImplItemKind::OpaqueTy(ref bounds) => {
|
||||
// If this is a trait impl, ensure the type
|
||||
// exists in trait
|
||||
this.check_trait_item(impl_item.ident,
|
||||
TypeNS,
|
||||
impl_item.span,
|
||||
|n, s| TypeNotMemberOfTrait(n, s));
|
||||
|
||||
for bound in bounds {
|
||||
this.visit_param_bound(bound);
|
||||
}
|
||||
}
|
||||
ImplItemKind::Macro(_) =>
|
||||
panic!("unexpanded macro in resolve!"),
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn check_trait_item<F>(&mut self, ident: Ident, ns: Namespace, span: Span, err: F)
|
||||
where F: FnOnce(Name, &str) -> ResolutionError<'_>
|
||||
{
|
||||
// If there is a TraitRef in scope for an impl, then the method must be in the
|
||||
// trait.
|
||||
if let Some((module, _)) = self.current_trait_ref {
|
||||
if self.r.resolve_ident_in_module(
|
||||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
ns,
|
||||
&self.parent_scope,
|
||||
false,
|
||||
span,
|
||||
).is_err() {
|
||||
let path = &self.current_trait_ref.as_ref().unwrap().1.path;
|
||||
self.r.report_error(span, err(ident.name, &path_names_to_string(path)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_local(&mut self, local: &Local) {
|
||||
// Resolve the type.
|
||||
walk_list!(self, visit_ty, &local.ty);
|
||||
|
||||
// Resolve the initializer.
|
||||
walk_list!(self, visit_expr, &local.init);
|
||||
|
||||
// Resolve the pattern.
|
||||
self.resolve_pattern(&local.pat, PatternSource::Let, &mut FxHashMap::default());
|
||||
}
|
||||
|
||||
// build a map from pattern identifiers to binding-info's.
|
||||
// this is done hygienically. This could arise for a macro
|
||||
// that expands into an or-pattern where one 'x' was from the
|
||||
// user and one 'x' came from the macro.
|
||||
fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap {
|
||||
let mut binding_map = FxHashMap::default();
|
||||
|
||||
pat.walk(&mut |pat| {
|
||||
if let PatKind::Ident(binding_mode, ident, ref sub_pat) = pat.node {
|
||||
if sub_pat.is_some() || match self.r.partial_res_map.get(&pat.id)
|
||||
.map(|res| res.base_res()) {
|
||||
Some(Res::Local(..)) => true,
|
||||
_ => false,
|
||||
} {
|
||||
let binding_info = BindingInfo { span: ident.span, binding_mode: binding_mode };
|
||||
binding_map.insert(ident, binding_info);
|
||||
}
|
||||
}
|
||||
true
|
||||
});
|
||||
|
||||
binding_map
|
||||
}
|
||||
|
||||
// Checks that all of the arms in an or-pattern have exactly the
|
||||
// same set of bindings, with the same binding modes for each.
|
||||
fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) {
|
||||
if pats.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut missing_vars = FxHashMap::default();
|
||||
let mut inconsistent_vars = FxHashMap::default();
|
||||
for (i, p) in pats.iter().enumerate() {
|
||||
let map_i = self.binding_mode_map(&p);
|
||||
|
||||
for (j, q) in pats.iter().enumerate() {
|
||||
if i == j {
|
||||
continue;
|
||||
}
|
||||
|
||||
let map_j = self.binding_mode_map(&q);
|
||||
for (&key, &binding_i) in &map_i {
|
||||
if map_j.is_empty() { // Account for missing bindings when
|
||||
let binding_error = missing_vars // `map_j` has none.
|
||||
.entry(key.name)
|
||||
.or_insert(BindingError {
|
||||
name: key.name,
|
||||
origin: BTreeSet::new(),
|
||||
target: BTreeSet::new(),
|
||||
});
|
||||
binding_error.origin.insert(binding_i.span);
|
||||
binding_error.target.insert(q.span);
|
||||
}
|
||||
for (&key_j, &binding_j) in &map_j {
|
||||
match map_i.get(&key_j) {
|
||||
None => { // missing binding
|
||||
let binding_error = missing_vars
|
||||
.entry(key_j.name)
|
||||
.or_insert(BindingError {
|
||||
name: key_j.name,
|
||||
origin: BTreeSet::new(),
|
||||
target: BTreeSet::new(),
|
||||
});
|
||||
binding_error.origin.insert(binding_j.span);
|
||||
binding_error.target.insert(p.span);
|
||||
}
|
||||
Some(binding_i) => { // check consistent binding
|
||||
if binding_i.binding_mode != binding_j.binding_mode {
|
||||
inconsistent_vars
|
||||
.entry(key.name)
|
||||
.or_insert((binding_j.span, binding_i.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut missing_vars = missing_vars.iter().collect::<Vec<_>>();
|
||||
missing_vars.sort();
|
||||
for (_, v) in missing_vars {
|
||||
self.r.report_error(
|
||||
*v.origin.iter().next().unwrap(), ResolutionError::VariableNotBoundInPattern(v)
|
||||
);
|
||||
}
|
||||
let mut inconsistent_vars = inconsistent_vars.iter().collect::<Vec<_>>();
|
||||
inconsistent_vars.sort();
|
||||
for (name, v) in inconsistent_vars {
|
||||
self.r.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1));
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_arm(&mut self, arm: &Arm) {
|
||||
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
|
||||
|
||||
self.resolve_pats(&arm.pats, PatternSource::Match);
|
||||
|
||||
if let Some(ref expr) = arm.guard {
|
||||
self.visit_expr(expr)
|
||||
}
|
||||
self.visit_expr(&arm.body);
|
||||
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
|
||||
/// Arising from `source`, resolve a sequence of patterns (top level or-patterns).
|
||||
fn resolve_pats(&mut self, pats: &[P<Pat>], source: PatternSource) {
|
||||
let mut bindings_list = FxHashMap::default();
|
||||
for pat in pats {
|
||||
self.resolve_pattern(pat, source, &mut bindings_list);
|
||||
}
|
||||
// This has to happen *after* we determine which pat_idents are variants
|
||||
self.check_consistent_bindings(pats);
|
||||
}
|
||||
|
||||
fn resolve_block(&mut self, block: &Block) {
|
||||
debug!("(resolving block) entering block");
|
||||
// Move down in the graph, if there's an anonymous module rooted here.
|
||||
let orig_module = self.parent_scope.module;
|
||||
let anonymous_module = self.r.block_map.get(&block.id).cloned(); // clones a reference
|
||||
|
||||
let mut num_macro_definition_ribs = 0;
|
||||
if let Some(anonymous_module) = anonymous_module {
|
||||
debug!("(resolving block) found anonymous module, moving down");
|
||||
self.ribs[ValueNS].push(Rib::new(ModuleRibKind(anonymous_module)));
|
||||
self.ribs[TypeNS].push(Rib::new(ModuleRibKind(anonymous_module)));
|
||||
self.parent_scope.module = anonymous_module;
|
||||
self.r.finalize_current_module_macro_resolutions(anonymous_module);
|
||||
} else {
|
||||
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
|
||||
}
|
||||
|
||||
// Descend into the block.
|
||||
for stmt in &block.stmts {
|
||||
if let StmtKind::Item(ref item) = stmt.node {
|
||||
if let ItemKind::MacroDef(..) = item.node {
|
||||
num_macro_definition_ribs += 1;
|
||||
let res = self.r.definitions.local_def_id(item.id);
|
||||
self.ribs[ValueNS].push(Rib::new(MacroDefinition(res)));
|
||||
self.label_ribs.push(Rib::new(MacroDefinition(res)));
|
||||
}
|
||||
}
|
||||
|
||||
self.visit_stmt(stmt);
|
||||
}
|
||||
|
||||
// Move back up.
|
||||
self.parent_scope.module = orig_module;
|
||||
for _ in 0 .. num_macro_definition_ribs {
|
||||
self.ribs[ValueNS].pop();
|
||||
self.label_ribs.pop();
|
||||
}
|
||||
self.ribs[ValueNS].pop();
|
||||
if anonymous_module.is_some() {
|
||||
self.ribs[TypeNS].pop();
|
||||
}
|
||||
debug!("(resolving block) leaving block");
|
||||
}
|
||||
|
||||
fn fresh_binding(&mut self,
|
||||
ident: Ident,
|
||||
pat_id: NodeId,
|
||||
outer_pat_id: NodeId,
|
||||
pat_src: PatternSource,
|
||||
bindings: &mut FxHashMap<Ident, NodeId>)
|
||||
-> Res {
|
||||
// Add the binding to the local ribs, if it
|
||||
// doesn't already exist in the bindings map. (We
|
||||
// must not add it if it's in the bindings map
|
||||
// because that breaks the assumptions later
|
||||
// passes make about or-patterns.)
|
||||
let ident = ident.modern_and_legacy();
|
||||
let mut res = Res::Local(pat_id);
|
||||
match bindings.get(&ident).cloned() {
|
||||
Some(id) if id == outer_pat_id => {
|
||||
// `Variant(a, a)`, error
|
||||
self.r.report_error(
|
||||
ident.span,
|
||||
ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(
|
||||
&ident.as_str())
|
||||
);
|
||||
}
|
||||
Some(..) if pat_src == PatternSource::FnParam => {
|
||||
// `fn f(a: u8, a: u8)`, error
|
||||
self.r.report_error(
|
||||
ident.span,
|
||||
ResolutionError::IdentifierBoundMoreThanOnceInParameterList(
|
||||
&ident.as_str())
|
||||
);
|
||||
}
|
||||
Some(..) if pat_src == PatternSource::Match ||
|
||||
pat_src == PatternSource::Let => {
|
||||
// `Variant1(a) | Variant2(a)`, ok
|
||||
// Reuse definition from the first `a`.
|
||||
res = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident];
|
||||
}
|
||||
Some(..) => {
|
||||
span_bug!(ident.span, "two bindings with the same name from \
|
||||
unexpected pattern source {:?}", pat_src);
|
||||
}
|
||||
None => {
|
||||
// A completely fresh binding, add to the lists if it's valid.
|
||||
if ident.name != kw::Invalid {
|
||||
bindings.insert(ident, outer_pat_id);
|
||||
self.ribs[ValueNS].last_mut().unwrap().bindings.insert(ident, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn resolve_pattern(&mut self,
|
||||
pat: &Pat,
|
||||
pat_src: PatternSource,
|
||||
// Maps idents to the node ID for the
|
||||
// outermost pattern that binds them.
|
||||
bindings: &mut FxHashMap<Ident, NodeId>) {
|
||||
// Visit all direct subpatterns of this pattern.
|
||||
let outer_pat_id = pat.id;
|
||||
pat.walk(&mut |pat| {
|
||||
debug!("resolve_pattern pat={:?} node={:?}", pat, pat.node);
|
||||
match pat.node {
|
||||
PatKind::Ident(bmode, ident, ref opt_pat) => {
|
||||
// First try to resolve the identifier as some existing
|
||||
// entity, then fall back to a fresh binding.
|
||||
let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS,
|
||||
None, pat.span)
|
||||
.and_then(LexicalScopeBinding::item);
|
||||
let res = binding.map(NameBinding::res).and_then(|res| {
|
||||
let is_syntactic_ambiguity = opt_pat.is_none() &&
|
||||
bmode == BindingMode::ByValue(Mutability::Immutable);
|
||||
match res {
|
||||
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) |
|
||||
Res::Def(DefKind::Const, _) if is_syntactic_ambiguity => {
|
||||
// Disambiguate in favor of a unit struct/variant
|
||||
// or constant pattern.
|
||||
self.r.record_use(ident, ValueNS, binding.unwrap(), false);
|
||||
Some(res)
|
||||
}
|
||||
Res::Def(DefKind::Ctor(..), _)
|
||||
| Res::Def(DefKind::Const, _)
|
||||
| Res::Def(DefKind::Static, _) => {
|
||||
// This is unambiguously a fresh binding, either syntactically
|
||||
// (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves
|
||||
// to something unusable as a pattern (e.g., constructor function),
|
||||
// but we still conservatively report an error, see
|
||||
// issues/33118#issuecomment-233962221 for one reason why.
|
||||
self.r.report_error(
|
||||
ident.span,
|
||||
ResolutionError::BindingShadowsSomethingUnacceptable(
|
||||
pat_src.descr(), ident.name, binding.unwrap())
|
||||
);
|
||||
None
|
||||
}
|
||||
Res::Def(DefKind::Fn, _) | Res::Err => {
|
||||
// These entities are explicitly allowed
|
||||
// to be shadowed by fresh bindings.
|
||||
None
|
||||
}
|
||||
res => {
|
||||
span_bug!(ident.span, "unexpected resolution for an \
|
||||
identifier in pattern: {:?}", res);
|
||||
}
|
||||
}
|
||||
}).unwrap_or_else(|| {
|
||||
self.fresh_binding(ident, pat.id, outer_pat_id, pat_src, bindings)
|
||||
});
|
||||
|
||||
self.r.record_partial_res(pat.id, PartialRes::new(res));
|
||||
}
|
||||
|
||||
PatKind::TupleStruct(ref path, ..) => {
|
||||
self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct);
|
||||
}
|
||||
|
||||
PatKind::Path(ref qself, ref path) => {
|
||||
self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat);
|
||||
}
|
||||
|
||||
PatKind::Struct(ref path, ..) => {
|
||||
self.smart_resolve_path(pat.id, None, path, PathSource::Struct);
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
true
|
||||
});
|
||||
|
||||
visit::walk_pat(self, pat);
|
||||
}
|
||||
|
||||
// High-level and context dependent path resolution routine.
|
||||
// Resolves the path and records the resolution into definition map.
|
||||
// If resolution fails tries several techniques to find likely
|
||||
// resolution candidates, suggest imports or other help, and report
|
||||
// errors in user friendly way.
|
||||
fn smart_resolve_path(&mut self,
|
||||
id: NodeId,
|
||||
qself: Option<&QSelf>,
|
||||
path: &Path,
|
||||
source: PathSource<'_>) {
|
||||
self.smart_resolve_path_fragment(
|
||||
id,
|
||||
qself,
|
||||
&Segment::from_path(path),
|
||||
path.span,
|
||||
source,
|
||||
CrateLint::SimplePath(id),
|
||||
);
|
||||
}
|
||||
|
||||
fn smart_resolve_path_fragment(&mut self,
|
||||
id: NodeId,
|
||||
qself: Option<&QSelf>,
|
||||
path: &[Segment],
|
||||
span: Span,
|
||||
source: PathSource<'_>,
|
||||
crate_lint: CrateLint)
|
||||
-> PartialRes {
|
||||
let ns = source.namespace();
|
||||
let is_expected = &|res| source.is_expected(res);
|
||||
|
||||
let report_errors = |this: &mut Self, res: Option<Res>| {
|
||||
let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res);
|
||||
let def_id = this.parent_scope.module.normal_ancestor_id;
|
||||
let node_id = this.r.definitions.as_local_node_id(def_id).unwrap();
|
||||
let better = res.is_some();
|
||||
this.r.use_injections.push(UseError { err, candidates, node_id, better });
|
||||
PartialRes::new(Res::Err)
|
||||
};
|
||||
|
||||
let partial_res = match self.resolve_qpath_anywhere(
|
||||
id,
|
||||
qself,
|
||||
path,
|
||||
ns,
|
||||
span,
|
||||
source.defer_to_typeck(),
|
||||
crate_lint,
|
||||
) {
|
||||
Some(partial_res) if partial_res.unresolved_segments() == 0 => {
|
||||
if is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err {
|
||||
partial_res
|
||||
} else {
|
||||
// Add a temporary hack to smooth the transition to new struct ctor
|
||||
// visibility rules. See #38932 for more details.
|
||||
let mut res = None;
|
||||
if let Res::Def(DefKind::Struct, def_id) = partial_res.base_res() {
|
||||
if let Some((ctor_res, ctor_vis))
|
||||
= self.r.struct_constructors.get(&def_id).cloned() {
|
||||
if is_expected(ctor_res) &&
|
||||
self.r.is_accessible_from(ctor_vis, self.parent_scope.module) {
|
||||
let lint = lint::builtin::LEGACY_CONSTRUCTOR_VISIBILITY;
|
||||
self.r.session.buffer_lint(lint, id, span,
|
||||
"private struct constructors are not usable through \
|
||||
re-exports in outer modules",
|
||||
);
|
||||
res = Some(PartialRes::new(ctor_res));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res.unwrap_or_else(|| report_errors(self, Some(partial_res.base_res())))
|
||||
}
|
||||
}
|
||||
Some(partial_res) if source.defer_to_typeck() => {
|
||||
// Not fully resolved associated item `T::A::B` or `<T as Tr>::A::B`
|
||||
// or `<T>::A::B`. If `B` should be resolved in value namespace then
|
||||
// it needs to be added to the trait map.
|
||||
if ns == ValueNS {
|
||||
let item_name = path.last().unwrap().ident;
|
||||
let traits = self.get_traits_containing_item(item_name, ns);
|
||||
self.r.trait_map.insert(id, traits);
|
||||
}
|
||||
|
||||
let mut std_path = vec![Segment::from_ident(Ident::with_empty_ctxt(sym::std))];
|
||||
std_path.extend(path);
|
||||
if self.r.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) {
|
||||
let cl = CrateLint::No;
|
||||
let ns = Some(ns);
|
||||
if let PathResult::Module(_) | PathResult::NonModule(_) =
|
||||
self.resolve_path(&std_path, ns, false, span, cl) {
|
||||
// check if we wrote `str::from_utf8` instead of `std::str::from_utf8`
|
||||
let item_span = path.iter().last().map(|segment| segment.ident.span)
|
||||
.unwrap_or(span);
|
||||
debug!("accessed item from `std` submodule as a bare type {:?}", std_path);
|
||||
let mut hm = self.r.session.confused_type_with_std_module.borrow_mut();
|
||||
hm.insert(item_span, span);
|
||||
// In some places (E0223) we only have access to the full path
|
||||
hm.insert(span, span);
|
||||
}
|
||||
}
|
||||
partial_res
|
||||
}
|
||||
_ => report_errors(self, None)
|
||||
};
|
||||
|
||||
if let PathSource::TraitItem(..) = source {} else {
|
||||
// Avoid recording definition of `A::B` in `<T as A>::B::C`.
|
||||
self.r.record_partial_res(id, partial_res);
|
||||
}
|
||||
partial_res
|
||||
}
|
||||
|
||||
fn self_type_is_available(&mut self, span: Span) -> bool {
|
||||
let binding = self.resolve_ident_in_lexical_scope(
|
||||
Ident::with_empty_ctxt(kw::SelfUpper),
|
||||
TypeNS,
|
||||
None,
|
||||
span,
|
||||
);
|
||||
if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
|
||||
}
|
||||
|
||||
fn self_value_is_available(&mut self, self_span: Span, path_span: Span) -> bool {
|
||||
let ident = Ident::new(kw::SelfLower, self_span);
|
||||
let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, path_span);
|
||||
if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
|
||||
}
|
||||
|
||||
// Resolve in alternative namespaces if resolution in the primary namespace fails.
|
||||
fn resolve_qpath_anywhere(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
qself: Option<&QSelf>,
|
||||
path: &[Segment],
|
||||
primary_ns: Namespace,
|
||||
span: Span,
|
||||
defer_to_typeck: bool,
|
||||
crate_lint: CrateLint,
|
||||
) -> Option<PartialRes> {
|
||||
let mut fin_res = None;
|
||||
for (i, ns) in [primary_ns, TypeNS, ValueNS].iter().cloned().enumerate() {
|
||||
if i == 0 || ns != primary_ns {
|
||||
match self.resolve_qpath(id, qself, path, ns, span, crate_lint) {
|
||||
// If defer_to_typeck, then resolution > no resolution,
|
||||
// otherwise full resolution > partial resolution > no resolution.
|
||||
Some(partial_res) if partial_res.unresolved_segments() == 0 ||
|
||||
defer_to_typeck =>
|
||||
return Some(partial_res),
|
||||
partial_res => if fin_res.is_none() { fin_res = partial_res },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// `MacroNS`
|
||||
assert!(primary_ns != MacroNS);
|
||||
if qself.is_none() {
|
||||
let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident);
|
||||
let path = Path { segments: path.iter().map(path_seg).collect(), span };
|
||||
if let Ok((_, res)) = self.r.resolve_macro_path(
|
||||
&path, None, &self.parent_scope, false, false
|
||||
) {
|
||||
return Some(PartialRes::new(res));
|
||||
}
|
||||
}
|
||||
|
||||
fin_res
|
||||
}
|
||||
|
||||
/// Handles paths that may refer to associated items.
|
||||
fn resolve_qpath(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
qself: Option<&QSelf>,
|
||||
path: &[Segment],
|
||||
ns: Namespace,
|
||||
span: Span,
|
||||
crate_lint: CrateLint,
|
||||
) -> Option<PartialRes> {
|
||||
debug!(
|
||||
"resolve_qpath(id={:?}, qself={:?}, path={:?}, ns={:?}, span={:?})",
|
||||
id,
|
||||
qself,
|
||||
path,
|
||||
ns,
|
||||
span,
|
||||
);
|
||||
|
||||
if let Some(qself) = qself {
|
||||
if qself.position == 0 {
|
||||
// This is a case like `<T>::B`, where there is no
|
||||
// trait to resolve. In that case, we leave the `B`
|
||||
// segment to be resolved by type-check.
|
||||
return Some(PartialRes::with_unresolved_segments(
|
||||
Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)), path.len()
|
||||
));
|
||||
}
|
||||
|
||||
// Make sure `A::B` in `<T as A::B>::C` is a trait item.
|
||||
//
|
||||
// Currently, `path` names the full item (`A::B::C`, in
|
||||
// our example). so we extract the prefix of that that is
|
||||
// the trait (the slice upto and including
|
||||
// `qself.position`). And then we recursively resolve that,
|
||||
// but with `qself` set to `None`.
|
||||
//
|
||||
// However, setting `qself` to none (but not changing the
|
||||
// span) loses the information about where this path
|
||||
// *actually* appears, so for the purposes of the crate
|
||||
// lint we pass along information that this is the trait
|
||||
// name from a fully qualified path, and this also
|
||||
// contains the full span (the `CrateLint::QPathTrait`).
|
||||
let ns = if qself.position + 1 == path.len() { ns } else { TypeNS };
|
||||
let partial_res = self.smart_resolve_path_fragment(
|
||||
id,
|
||||
None,
|
||||
&path[..=qself.position],
|
||||
span,
|
||||
PathSource::TraitItem(ns),
|
||||
CrateLint::QPathTrait {
|
||||
qpath_id: id,
|
||||
qpath_span: qself.path_span,
|
||||
},
|
||||
);
|
||||
|
||||
// The remaining segments (the `C` in our example) will
|
||||
// have to be resolved by type-check, since that requires doing
|
||||
// trait resolution.
|
||||
return Some(PartialRes::with_unresolved_segments(
|
||||
partial_res.base_res(),
|
||||
partial_res.unresolved_segments() + path.len() - qself.position - 1,
|
||||
));
|
||||
}
|
||||
|
||||
let result = match self.resolve_path(&path, Some(ns), true, span, crate_lint) {
|
||||
PathResult::NonModule(path_res) => path_res,
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => {
|
||||
PartialRes::new(module.res().unwrap())
|
||||
}
|
||||
// In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we
|
||||
// don't report an error right away, but try to fallback to a primitive type.
|
||||
// So, we are still able to successfully resolve something like
|
||||
//
|
||||
// use std::u8; // bring module u8 in scope
|
||||
// fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8
|
||||
// u8::max_value() // OK, resolves to associated function <u8>::max_value,
|
||||
// // not to non-existent std::u8::max_value
|
||||
// }
|
||||
//
|
||||
// Such behavior is required for backward compatibility.
|
||||
// The same fallback is used when `a` resolves to nothing.
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(_)) |
|
||||
PathResult::Failed { .. }
|
||||
if (ns == TypeNS || path.len() > 1) &&
|
||||
self.r.primitive_type_table.primitive_types
|
||||
.contains_key(&path[0].ident.name) => {
|
||||
let prim = self.r.primitive_type_table.primitive_types[&path[0].ident.name];
|
||||
PartialRes::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1)
|
||||
}
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
|
||||
PartialRes::new(module.res().unwrap()),
|
||||
PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
|
||||
self.r.report_error(span, ResolutionError::FailedToResolve { label, suggestion });
|
||||
PartialRes::new(Res::Err)
|
||||
}
|
||||
PathResult::Module(..) | PathResult::Failed { .. } => return None,
|
||||
PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"),
|
||||
};
|
||||
|
||||
if path.len() > 1 && result.base_res() != Res::Err &&
|
||||
path[0].ident.name != kw::PathRoot &&
|
||||
path[0].ident.name != kw::DollarCrate {
|
||||
let unqualified_result = {
|
||||
match self.resolve_path(
|
||||
&[*path.last().unwrap()],
|
||||
Some(ns),
|
||||
false,
|
||||
span,
|
||||
CrateLint::No,
|
||||
) {
|
||||
PathResult::NonModule(path_res) => path_res.base_res(),
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
|
||||
module.res().unwrap(),
|
||||
_ => return Some(result),
|
||||
}
|
||||
};
|
||||
if result.base_res() == unqualified_result {
|
||||
let lint = lint::builtin::UNUSED_QUALIFICATIONS;
|
||||
self.r.session.buffer_lint(lint, id, span, "unnecessary qualification")
|
||||
}
|
||||
}
|
||||
|
||||
Some(result)
|
||||
}
|
||||
|
||||
fn with_resolved_label<F>(&mut self, label: Option<Label>, id: NodeId, f: F)
|
||||
where F: FnOnce(&mut LateResolutionVisitor<'_, '_>)
|
||||
{
|
||||
if let Some(label) = label {
|
||||
self.unused_labels.insert(id, label.ident.span);
|
||||
self.with_label_rib(|this| {
|
||||
let ident = label.ident.modern_and_legacy();
|
||||
this.label_ribs.last_mut().unwrap().bindings.insert(ident, id);
|
||||
f(this);
|
||||
});
|
||||
} else {
|
||||
f(self);
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_labeled_block(&mut self, label: Option<Label>, id: NodeId, block: &Block) {
|
||||
self.with_resolved_label(label, id, |this| this.visit_block(block));
|
||||
}
|
||||
|
||||
fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
|
||||
// First, record candidate traits for this expression if it could
|
||||
// result in the invocation of a method call.
|
||||
|
||||
self.record_candidate_traits_for_expr_if_necessary(expr);
|
||||
|
||||
// Next, resolve the node.
|
||||
match expr.node {
|
||||
ExprKind::Path(ref qself, ref path) => {
|
||||
self.smart_resolve_path(expr.id, qself.as_ref(), path, PathSource::Expr(parent));
|
||||
visit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
ExprKind::Struct(ref path, ..) => {
|
||||
self.smart_resolve_path(expr.id, None, path, PathSource::Struct);
|
||||
visit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
|
||||
let node_id = self.search_label(label.ident, |rib, ident| {
|
||||
rib.bindings.get(&ident.modern_and_legacy()).cloned()
|
||||
});
|
||||
match node_id {
|
||||
None => {
|
||||
// Search again for close matches...
|
||||
// Picks the first label that is "close enough", which is not necessarily
|
||||
// the closest match
|
||||
let close_match = self.search_label(label.ident, |rib, ident| {
|
||||
let names = rib.bindings.iter().filter_map(|(id, _)| {
|
||||
if id.span.ctxt() == label.ident.span.ctxt() {
|
||||
Some(&id.name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
find_best_match_for_name(names, &*ident.as_str(), None)
|
||||
});
|
||||
self.r.record_partial_res(expr.id, PartialRes::new(Res::Err));
|
||||
self.r.report_error(
|
||||
label.ident.span,
|
||||
ResolutionError::UndeclaredLabel(&label.ident.as_str(), close_match),
|
||||
);
|
||||
}
|
||||
Some(node_id) => {
|
||||
// Since this res is a label, it is never read.
|
||||
self.r.label_res_map.insert(expr.id, node_id);
|
||||
self.unused_labels.remove(&node_id);
|
||||
}
|
||||
}
|
||||
|
||||
// visit `break` argument if any
|
||||
visit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
ExprKind::Let(ref pats, ref scrutinee) => {
|
||||
self.visit_expr(scrutinee);
|
||||
self.resolve_pats(pats, PatternSource::Let);
|
||||
}
|
||||
|
||||
ExprKind::If(ref cond, ref then, ref opt_else) => {
|
||||
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
|
||||
self.visit_expr(cond);
|
||||
self.visit_block(then);
|
||||
self.ribs[ValueNS].pop();
|
||||
|
||||
opt_else.as_ref().map(|expr| self.visit_expr(expr));
|
||||
}
|
||||
|
||||
ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block),
|
||||
|
||||
ExprKind::While(ref subexpression, ref block, label) => {
|
||||
self.with_resolved_label(label, expr.id, |this| {
|
||||
this.ribs[ValueNS].push(Rib::new(NormalRibKind));
|
||||
this.visit_expr(subexpression);
|
||||
this.visit_block(block);
|
||||
this.ribs[ValueNS].pop();
|
||||
});
|
||||
}
|
||||
|
||||
ExprKind::ForLoop(ref pattern, ref subexpression, ref block, label) => {
|
||||
self.visit_expr(subexpression);
|
||||
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
|
||||
self.resolve_pattern(pattern, PatternSource::For, &mut FxHashMap::default());
|
||||
|
||||
self.resolve_labeled_block(label, expr.id, block);
|
||||
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
|
||||
ExprKind::Block(ref block, label) => self.resolve_labeled_block(label, block.id, block),
|
||||
|
||||
// Equivalent to `visit::walk_expr` + passing some context to children.
|
||||
ExprKind::Field(ref subexpression, _) => {
|
||||
self.resolve_expr(subexpression, Some(expr));
|
||||
}
|
||||
ExprKind::MethodCall(ref segment, ref arguments) => {
|
||||
let mut arguments = arguments.iter();
|
||||
self.resolve_expr(arguments.next().unwrap(), Some(expr));
|
||||
for argument in arguments {
|
||||
self.resolve_expr(argument, None);
|
||||
}
|
||||
self.visit_path_segment(expr.span, segment);
|
||||
}
|
||||
|
||||
ExprKind::Call(ref callee, ref arguments) => {
|
||||
self.resolve_expr(callee, Some(expr));
|
||||
for argument in arguments {
|
||||
self.resolve_expr(argument, None);
|
||||
}
|
||||
}
|
||||
ExprKind::Type(ref type_expr, _) => {
|
||||
self.current_type_ascription.push(type_expr.span);
|
||||
visit::walk_expr(self, expr);
|
||||
self.current_type_ascription.pop();
|
||||
}
|
||||
// `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to
|
||||
// resolve the arguments within the proper scopes so that usages of them inside the
|
||||
// closure are detected as upvars rather than normal closure arg usages.
|
||||
ExprKind::Closure(
|
||||
_, IsAsync::Async { .. }, _,
|
||||
ref fn_decl, ref body, _span,
|
||||
) => {
|
||||
let rib_kind = NormalRibKind;
|
||||
self.ribs[ValueNS].push(Rib::new(rib_kind));
|
||||
// Resolve arguments:
|
||||
let mut bindings_list = FxHashMap::default();
|
||||
for argument in &fn_decl.inputs {
|
||||
self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
|
||||
self.visit_ty(&argument.ty);
|
||||
}
|
||||
// No need to resolve return type-- the outer closure return type is
|
||||
// FunctionRetTy::Default
|
||||
|
||||
// Now resolve the inner closure
|
||||
{
|
||||
// No need to resolve arguments: the inner closure has none.
|
||||
// Resolve the return type:
|
||||
visit::walk_fn_ret_ty(self, &fn_decl.output);
|
||||
// Resolve the body
|
||||
self.visit_expr(body);
|
||||
}
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
_ => {
|
||||
visit::walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &Expr) {
|
||||
match expr.node {
|
||||
ExprKind::Field(_, ident) => {
|
||||
// FIXME(#6890): Even though you can't treat a method like a
|
||||
// field, we need to add any trait methods we find that match
|
||||
// the field name so that we can do some nice error reporting
|
||||
// later on in typeck.
|
||||
let traits = self.get_traits_containing_item(ident, ValueNS);
|
||||
self.r.trait_map.insert(expr.id, traits);
|
||||
}
|
||||
ExprKind::MethodCall(ref segment, ..) => {
|
||||
debug!("(recording candidate traits for expr) recording traits for {}",
|
||||
expr.id);
|
||||
let traits = self.get_traits_containing_item(segment.ident, ValueNS);
|
||||
self.r.trait_map.insert(expr.id, traits);
|
||||
}
|
||||
_ => {
|
||||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_traits_containing_item(&mut self, mut ident: Ident, ns: Namespace)
|
||||
-> Vec<TraitCandidate> {
|
||||
debug!("(getting traits containing item) looking for '{}'", ident.name);
|
||||
|
||||
let mut found_traits = Vec::new();
|
||||
// Look for the current trait.
|
||||
if let Some((module, _)) = self.current_trait_ref {
|
||||
if self.r.resolve_ident_in_module(
|
||||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
ns,
|
||||
&self.parent_scope,
|
||||
false,
|
||||
module.span,
|
||||
).is_ok() {
|
||||
let def_id = module.def_id().unwrap();
|
||||
found_traits.push(TraitCandidate { def_id: def_id, import_ids: smallvec![] });
|
||||
}
|
||||
}
|
||||
|
||||
ident.span = ident.span.modern();
|
||||
let mut search_module = self.parent_scope.module;
|
||||
loop {
|
||||
self.get_traits_in_module_containing_item(ident, ns, search_module, &mut found_traits);
|
||||
search_module = unwrap_or!(
|
||||
self.r.hygienic_lexical_parent(search_module, &mut ident.span), break
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(prelude) = self.r.prelude {
|
||||
if !search_module.no_implicit_prelude {
|
||||
self.get_traits_in_module_containing_item(ident, ns, prelude, &mut found_traits);
|
||||
}
|
||||
}
|
||||
|
||||
found_traits
|
||||
}
|
||||
|
||||
fn get_traits_in_module_containing_item(&mut self,
|
||||
ident: Ident,
|
||||
ns: Namespace,
|
||||
module: Module<'a>,
|
||||
found_traits: &mut Vec<TraitCandidate>) {
|
||||
assert!(ns == TypeNS || ns == ValueNS);
|
||||
let mut traits = module.traits.borrow_mut();
|
||||
if traits.is_none() {
|
||||
let mut collected_traits = Vec::new();
|
||||
module.for_each_child(|name, ns, binding| {
|
||||
if ns != TypeNS { return }
|
||||
match binding.res() {
|
||||
Res::Def(DefKind::Trait, _) |
|
||||
Res::Def(DefKind::TraitAlias, _) => collected_traits.push((name, binding)),
|
||||
_ => (),
|
||||
}
|
||||
});
|
||||
*traits = Some(collected_traits.into_boxed_slice());
|
||||
}
|
||||
|
||||
for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
|
||||
// Traits have pseudo-modules that can be used to search for the given ident.
|
||||
if let Some(module) = binding.module() {
|
||||
let mut ident = ident;
|
||||
if ident.span.glob_adjust(
|
||||
module.expansion,
|
||||
binding.span,
|
||||
).is_none() {
|
||||
continue
|
||||
}
|
||||
if self.r.resolve_ident_in_module_unadjusted(
|
||||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
ns,
|
||||
&self.parent_scope,
|
||||
false,
|
||||
module.span,
|
||||
).is_ok() {
|
||||
let import_ids = self.find_transitive_imports(&binding.kind, trait_name);
|
||||
let trait_def_id = module.def_id().unwrap();
|
||||
found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
|
||||
}
|
||||
} else if let Res::Def(DefKind::TraitAlias, _) = binding.res() {
|
||||
// For now, just treat all trait aliases as possible candidates, since we don't
|
||||
// know if the ident is somewhere in the transitive bounds.
|
||||
let import_ids = self.find_transitive_imports(&binding.kind, trait_name);
|
||||
let trait_def_id = binding.res().def_id();
|
||||
found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
|
||||
} else {
|
||||
bug!("candidate is not trait or trait alias?")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_transitive_imports(&mut self, mut kind: &NameBindingKind<'_>,
|
||||
trait_name: Ident) -> SmallVec<[NodeId; 1]> {
|
||||
let mut import_ids = smallvec![];
|
||||
while let NameBindingKind::Import { directive, binding, .. } = kind {
|
||||
self.r.maybe_unused_trait_imports.insert(directive.id);
|
||||
self.r.add_to_glob_map(&directive, trait_name);
|
||||
import_ids.push(directive.id);
|
||||
kind = &binding.kind;
|
||||
};
|
||||
import_ids
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Resolver<'a> {
|
||||
pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) {
|
||||
self.finalize_current_module_macro_resolutions(self.graph_root);
|
||||
let mut late_resolution_visitor = LateResolutionVisitor::new(self);
|
||||
visit::walk_crate(&mut late_resolution_visitor, krate);
|
||||
for (id, span) in late_resolution_visitor.unused_labels.iter() {
|
||||
self.session.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
+161
-2580
@@ -1,5 +1,3 @@
|
||||
// ignore-tidy-filelength
|
||||
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
|
||||
|
||||
#![feature(crate_visibility_modifier)]
|
||||
@@ -13,60 +11,48 @@
|
||||
pub use rustc::hir::def::{Namespace, PerNS};
|
||||
|
||||
use Determinacy::*;
|
||||
use GenericParameters::*;
|
||||
use RibKind::*;
|
||||
use smallvec::smallvec;
|
||||
|
||||
use rustc::hir::map::Definitions;
|
||||
use rustc::hir::{self, PrimTy, Bool, Char, Float, Int, Uint, Str};
|
||||
use rustc::middle::cstore::CrateStore;
|
||||
use rustc::session::Session;
|
||||
use rustc::lint;
|
||||
use rustc::hir::def::{
|
||||
self, DefKind, PartialRes, CtorKind, CtorOf, NonMacroAttrKind, ExportMap
|
||||
};
|
||||
use rustc::hir::def::{self, DefKind, PartialRes, CtorKind, CtorOf, NonMacroAttrKind, ExportMap};
|
||||
use rustc::hir::def::Namespace::*;
|
||||
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
|
||||
use rustc::hir::{TraitCandidate, TraitMap, GlobMap};
|
||||
use rustc::hir::{TraitMap, GlobMap};
|
||||
use rustc::ty;
|
||||
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
|
||||
use rustc::{bug, span_bug};
|
||||
use rustc::span_bug;
|
||||
|
||||
use rustc_metadata::creader::CrateLoader;
|
||||
use rustc_metadata::cstore::CStore;
|
||||
|
||||
use syntax::source_map::SourceMap;
|
||||
use syntax::ext::hygiene::{ExpnId, Transparency, SyntaxContext};
|
||||
use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy};
|
||||
use syntax::ext::base::{SyntaxExtension, MacroKind, SpecialDerives};
|
||||
use syntax::symbol::{Symbol, kw, sym};
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
|
||||
use syntax::visit::{self, FnKind, Visitor};
|
||||
use syntax::visit::{self, Visitor};
|
||||
use syntax::attr;
|
||||
use syntax::ast::{CRATE_NODE_ID, Arm, IsAsync, BindingMode, Block, Crate, Expr, ExprKind};
|
||||
use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generics};
|
||||
use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
|
||||
use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
|
||||
use syntax::ast::{QSelf, TraitItem, TraitItemKind, TraitRef, Ty, TyKind};
|
||||
use syntax::ptr::P;
|
||||
use syntax::{struct_span_err, unwrap_or, walk_list};
|
||||
use syntax::ast::{CRATE_NODE_ID, Crate};
|
||||
use syntax::ast::{ItemKind, Path};
|
||||
use syntax::{struct_span_err, unwrap_or};
|
||||
|
||||
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
|
||||
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use errors::{Applicability, DiagnosticBuilder};
|
||||
|
||||
use log::debug;
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::{cmp, fmt, iter, mem, ptr};
|
||||
use std::{cmp, fmt, iter, ptr};
|
||||
use std::collections::BTreeSet;
|
||||
use std::mem::replace;
|
||||
use rustc_data_structures::ptr_key::PtrKey;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use diagnostics::{Suggestion, ImportSuggestion};
|
||||
use diagnostics::{find_span_of_binding_until_next_binding, extend_span_to_previous_binding};
|
||||
use late::{PathSource, Rib, RibKind::*};
|
||||
use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
|
||||
use macros::{InvocationData, LegacyBinding, LegacyScope};
|
||||
|
||||
@@ -76,6 +62,7 @@
|
||||
// registered before they are used.
|
||||
mod error_codes;
|
||||
mod diagnostics;
|
||||
mod late;
|
||||
mod macros;
|
||||
mod check_unused;
|
||||
mod build_reduced_graph;
|
||||
@@ -123,10 +110,12 @@ enum Scope<'a> {
|
||||
/// This enum is currently used only for early resolution (imports and macros),
|
||||
/// but not for late resolution yet.
|
||||
enum ScopeSet {
|
||||
Import(Namespace),
|
||||
/// All scopes with the given namespace.
|
||||
All(Namespace, /*is_import*/ bool),
|
||||
/// Crate root, then extern prelude (used for mixed 2015-2018 mode in macros).
|
||||
AbsolutePath(Namespace),
|
||||
/// All scopes with macro namespace and the given macro kind restriction.
|
||||
Macro(MacroKind),
|
||||
Module,
|
||||
}
|
||||
|
||||
/// Everything you need to know about a name's location to resolve it.
|
||||
@@ -208,494 +197,6 @@ enum ResolutionError<'a> {
|
||||
ConstParamDependentOnTypeParam,
|
||||
}
|
||||
|
||||
/// Combines an error with provided span and emits it.
|
||||
///
|
||||
/// This takes the error provided, combines it with the span and any additional spans inside the
|
||||
/// error and emits it.
|
||||
fn resolve_error(resolver: &Resolver<'_>,
|
||||
span: Span,
|
||||
resolution_error: ResolutionError<'_>) {
|
||||
resolve_struct_error(resolver, span, resolution_error).emit();
|
||||
}
|
||||
|
||||
fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
|
||||
span: Span,
|
||||
resolution_error: ResolutionError<'a>)
|
||||
-> DiagnosticBuilder<'sess> {
|
||||
match resolution_error {
|
||||
ResolutionError::GenericParamsFromOuterFunction(outer_res) => {
|
||||
let mut err = struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0401,
|
||||
"can't use generic parameters from outer function",
|
||||
);
|
||||
err.span_label(span, format!("use of generic parameter from outer function"));
|
||||
|
||||
let cm = resolver.session.source_map();
|
||||
match outer_res {
|
||||
Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
|
||||
if let Some(impl_span) = maybe_impl_defid.and_then(|def_id| {
|
||||
resolver.definitions.opt_span(def_id)
|
||||
}) {
|
||||
err.span_label(
|
||||
reduce_impl_span_to_impl_keyword(cm, impl_span),
|
||||
"`Self` type implicitly declared here, by this `impl`",
|
||||
);
|
||||
}
|
||||
match (maybe_trait_defid, maybe_impl_defid) {
|
||||
(Some(_), None) => {
|
||||
err.span_label(span, "can't use `Self` here");
|
||||
}
|
||||
(_, Some(_)) => {
|
||||
err.span_label(span, "use a type here instead");
|
||||
}
|
||||
(None, None) => bug!("`impl` without trait nor type?"),
|
||||
}
|
||||
return err;
|
||||
},
|
||||
Res::Def(DefKind::TyParam, def_id) => {
|
||||
if let Some(span) = resolver.definitions.opt_span(def_id) {
|
||||
err.span_label(span, "type parameter from outer function");
|
||||
}
|
||||
}
|
||||
Res::Def(DefKind::ConstParam, def_id) => {
|
||||
if let Some(span) = resolver.definitions.opt_span(def_id) {
|
||||
err.span_label(span, "const parameter from outer function");
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
bug!("GenericParamsFromOuterFunction should only be used with Res::SelfTy, \
|
||||
DefKind::TyParam");
|
||||
}
|
||||
}
|
||||
|
||||
// Try to retrieve the span of the function signature and generate a new message with
|
||||
// a local type or const parameter.
|
||||
let sugg_msg = &format!("try using a local generic parameter instead");
|
||||
if let Some((sugg_span, new_snippet)) = cm.generate_local_type_param_snippet(span) {
|
||||
// Suggest the modification to the user
|
||||
err.span_suggestion(
|
||||
sugg_span,
|
||||
sugg_msg,
|
||||
new_snippet,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if let Some(sp) = cm.generate_fn_name_span(span) {
|
||||
err.span_label(sp,
|
||||
format!("try adding a local generic parameter in this method instead"));
|
||||
} else {
|
||||
err.help(&format!("try using a local generic parameter instead"));
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => {
|
||||
let mut err = struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0403,
|
||||
"the name `{}` is already used for a generic \
|
||||
parameter in this list of generic parameters",
|
||||
name);
|
||||
err.span_label(span, "already used");
|
||||
err.span_label(first_use_span, format!("first use of `{}`", name));
|
||||
err
|
||||
}
|
||||
ResolutionError::MethodNotMemberOfTrait(method, trait_) => {
|
||||
let mut err = struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0407,
|
||||
"method `{}` is not a member of trait `{}`",
|
||||
method,
|
||||
trait_);
|
||||
err.span_label(span, format!("not a member of trait `{}`", trait_));
|
||||
err
|
||||
}
|
||||
ResolutionError::TypeNotMemberOfTrait(type_, trait_) => {
|
||||
let mut err = struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0437,
|
||||
"type `{}` is not a member of trait `{}`",
|
||||
type_,
|
||||
trait_);
|
||||
err.span_label(span, format!("not a member of trait `{}`", trait_));
|
||||
err
|
||||
}
|
||||
ResolutionError::ConstNotMemberOfTrait(const_, trait_) => {
|
||||
let mut err = struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0438,
|
||||
"const `{}` is not a member of trait `{}`",
|
||||
const_,
|
||||
trait_);
|
||||
err.span_label(span, format!("not a member of trait `{}`", trait_));
|
||||
err
|
||||
}
|
||||
ResolutionError::VariableNotBoundInPattern(binding_error) => {
|
||||
let target_sp = binding_error.target.iter().cloned().collect::<Vec<_>>();
|
||||
let msp = MultiSpan::from_spans(target_sp.clone());
|
||||
let msg = format!("variable `{}` is not bound in all patterns", binding_error.name);
|
||||
let mut err = resolver.session.struct_span_err_with_code(
|
||||
msp,
|
||||
&msg,
|
||||
DiagnosticId::Error("E0408".into()),
|
||||
);
|
||||
for sp in target_sp {
|
||||
err.span_label(sp, format!("pattern doesn't bind `{}`", binding_error.name));
|
||||
}
|
||||
let origin_sp = binding_error.origin.iter().cloned();
|
||||
for sp in origin_sp {
|
||||
err.span_label(sp, "variable not in all patterns");
|
||||
}
|
||||
err
|
||||
}
|
||||
ResolutionError::VariableBoundWithDifferentMode(variable_name,
|
||||
first_binding_span) => {
|
||||
let mut err = struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0409,
|
||||
"variable `{}` is bound in inconsistent \
|
||||
ways within the same match arm",
|
||||
variable_name);
|
||||
err.span_label(span, "bound in different ways");
|
||||
err.span_label(first_binding_span, "first binding");
|
||||
err
|
||||
}
|
||||
ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => {
|
||||
let mut err = struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0415,
|
||||
"identifier `{}` is bound more than once in this parameter list",
|
||||
identifier);
|
||||
err.span_label(span, "used as parameter more than once");
|
||||
err
|
||||
}
|
||||
ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => {
|
||||
let mut err = struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0416,
|
||||
"identifier `{}` is bound more than once in the same pattern",
|
||||
identifier);
|
||||
err.span_label(span, "used in a pattern more than once");
|
||||
err
|
||||
}
|
||||
ResolutionError::UndeclaredLabel(name, lev_candidate) => {
|
||||
let mut err = struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0426,
|
||||
"use of undeclared label `{}`",
|
||||
name);
|
||||
if let Some(lev_candidate) = lev_candidate {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"a label with a similar name exists in this scope",
|
||||
lev_candidate.to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.span_label(span, format!("undeclared label `{}`", name));
|
||||
}
|
||||
err
|
||||
}
|
||||
ResolutionError::SelfImportsOnlyAllowedWithin => {
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0429,
|
||||
"{}",
|
||||
"`self` imports are only allowed within a { } list")
|
||||
}
|
||||
ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
|
||||
let mut err = struct_span_err!(resolver.session, span, E0430,
|
||||
"`self` import can only appear once in an import list");
|
||||
err.span_label(span, "can only appear once in an import list");
|
||||
err
|
||||
}
|
||||
ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
|
||||
let mut err = struct_span_err!(resolver.session, span, E0431,
|
||||
"`self` import can only appear in an import list with \
|
||||
a non-empty prefix");
|
||||
err.span_label(span, "can only appear in an import list with a non-empty prefix");
|
||||
err
|
||||
}
|
||||
ResolutionError::FailedToResolve { label, suggestion } => {
|
||||
let mut err = struct_span_err!(resolver.session, span, E0433,
|
||||
"failed to resolve: {}", &label);
|
||||
err.span_label(span, label);
|
||||
|
||||
if let Some((suggestions, msg, applicability)) = suggestion {
|
||||
err.multipart_suggestion(&msg, suggestions, applicability);
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
|
||||
let mut err = struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0434,
|
||||
"{}",
|
||||
"can't capture dynamic environment in a fn item");
|
||||
err.help("use the `|| { ... }` closure form instead");
|
||||
err
|
||||
}
|
||||
ResolutionError::AttemptToUseNonConstantValueInConstant => {
|
||||
let mut err = struct_span_err!(resolver.session, span, E0435,
|
||||
"attempt to use a non-constant value in a constant");
|
||||
err.span_label(span, "non-constant value");
|
||||
err
|
||||
}
|
||||
ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => {
|
||||
let shadows_what = binding.descr();
|
||||
let mut err = struct_span_err!(resolver.session, span, E0530, "{}s cannot shadow {}s",
|
||||
what_binding, shadows_what);
|
||||
err.span_label(span, format!("cannot be named the same as {} {}",
|
||||
binding.article(), shadows_what));
|
||||
let participle = if binding.is_import() { "imported" } else { "defined" };
|
||||
let msg = format!("the {} `{}` is {} here", shadows_what, name, participle);
|
||||
err.span_label(binding.span, msg);
|
||||
err
|
||||
}
|
||||
ResolutionError::ForwardDeclaredTyParam => {
|
||||
let mut err = struct_span_err!(resolver.session, span, E0128,
|
||||
"type parameters with a default cannot use \
|
||||
forward declared identifiers");
|
||||
err.span_label(
|
||||
span, "defaulted type parameters cannot be forward declared".to_string());
|
||||
err
|
||||
}
|
||||
ResolutionError::ConstParamDependentOnTypeParam => {
|
||||
let mut err = struct_span_err!(
|
||||
resolver.session,
|
||||
span,
|
||||
E0671,
|
||||
"const parameters cannot depend on type parameters"
|
||||
);
|
||||
err.span_label(span, format!("const parameter depends on type parameter"));
|
||||
err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Adjust the impl span so that just the `impl` keyword is taken by removing
|
||||
/// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "impl"`) and
|
||||
/// everything after the first whitespace (`"impl Iterator for A" -> "impl"`).
|
||||
///
|
||||
/// *Attention*: the method used is very fragile since it essentially duplicates the work of the
|
||||
/// parser. If you need to use this function or something similar, please consider updating the
|
||||
/// `source_map` functions and this function to something more robust.
|
||||
fn reduce_impl_span_to_impl_keyword(cm: &SourceMap, impl_span: Span) -> Span {
|
||||
let impl_span = cm.span_until_char(impl_span, '<');
|
||||
let impl_span = cm.span_until_whitespace(impl_span);
|
||||
impl_span
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct BindingInfo {
|
||||
span: Span,
|
||||
binding_mode: BindingMode,
|
||||
}
|
||||
|
||||
/// Map from the name in a pattern to its binding mode.
|
||||
type BindingMap = FxHashMap<Ident, BindingInfo>;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
enum PatternSource {
|
||||
Match,
|
||||
Let,
|
||||
For,
|
||||
FnParam,
|
||||
}
|
||||
|
||||
impl PatternSource {
|
||||
fn descr(self) -> &'static str {
|
||||
match self {
|
||||
PatternSource::Match => "match binding",
|
||||
PatternSource::Let => "let binding",
|
||||
PatternSource::For => "for binding",
|
||||
PatternSource::FnParam => "function parameter",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
enum AliasPossibility {
|
||||
No,
|
||||
Maybe,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum PathSource<'a> {
|
||||
// Type paths `Path`.
|
||||
Type,
|
||||
// Trait paths in bounds or impls.
|
||||
Trait(AliasPossibility),
|
||||
// Expression paths `path`, with optional parent context.
|
||||
Expr(Option<&'a Expr>),
|
||||
// Paths in path patterns `Path`.
|
||||
Pat,
|
||||
// Paths in struct expressions and patterns `Path { .. }`.
|
||||
Struct,
|
||||
// Paths in tuple struct patterns `Path(..)`.
|
||||
TupleStruct,
|
||||
// `m::A::B` in `<T as m::A>::B::C`.
|
||||
TraitItem(Namespace),
|
||||
// Path in `pub(path)`
|
||||
Visibility,
|
||||
}
|
||||
|
||||
impl<'a> PathSource<'a> {
|
||||
fn namespace(self) -> Namespace {
|
||||
match self {
|
||||
PathSource::Type | PathSource::Trait(_) | PathSource::Struct |
|
||||
PathSource::Visibility => TypeNS,
|
||||
PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS,
|
||||
PathSource::TraitItem(ns) => ns,
|
||||
}
|
||||
}
|
||||
|
||||
fn global_by_default(self) -> bool {
|
||||
match self {
|
||||
PathSource::Visibility => true,
|
||||
PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
|
||||
PathSource::Struct | PathSource::TupleStruct |
|
||||
PathSource::Trait(_) | PathSource::TraitItem(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn defer_to_typeck(self) -> bool {
|
||||
match self {
|
||||
PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
|
||||
PathSource::Struct | PathSource::TupleStruct => true,
|
||||
PathSource::Trait(_) | PathSource::TraitItem(..) |
|
||||
PathSource::Visibility => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn descr_expected(self) -> &'static str {
|
||||
match self {
|
||||
PathSource::Type => "type",
|
||||
PathSource::Trait(_) => "trait",
|
||||
PathSource::Pat => "unit struct/variant or constant",
|
||||
PathSource::Struct => "struct, variant or union type",
|
||||
PathSource::TupleStruct => "tuple struct/variant",
|
||||
PathSource::Visibility => "module",
|
||||
PathSource::TraitItem(ns) => match ns {
|
||||
TypeNS => "associated type",
|
||||
ValueNS => "method or associated constant",
|
||||
MacroNS => bug!("associated macro"),
|
||||
},
|
||||
PathSource::Expr(parent) => match parent.map(|p| &p.node) {
|
||||
// "function" here means "anything callable" rather than `DefKind::Fn`,
|
||||
// this is not precise but usually more helpful than just "value".
|
||||
Some(&ExprKind::Call(..)) => "function",
|
||||
_ => "value",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn is_expected(self, res: Res) -> bool {
|
||||
match self {
|
||||
PathSource::Type => match res {
|
||||
Res::Def(DefKind::Struct, _)
|
||||
| Res::Def(DefKind::Union, _)
|
||||
| Res::Def(DefKind::Enum, _)
|
||||
| Res::Def(DefKind::Trait, _)
|
||||
| Res::Def(DefKind::TraitAlias, _)
|
||||
| Res::Def(DefKind::TyAlias, _)
|
||||
| Res::Def(DefKind::AssocTy, _)
|
||||
| Res::PrimTy(..)
|
||||
| Res::Def(DefKind::TyParam, _)
|
||||
| Res::SelfTy(..)
|
||||
| Res::Def(DefKind::OpaqueTy, _)
|
||||
| Res::Def(DefKind::ForeignTy, _) => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::Trait(AliasPossibility::No) => match res {
|
||||
Res::Def(DefKind::Trait, _) => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::Trait(AliasPossibility::Maybe) => match res {
|
||||
Res::Def(DefKind::Trait, _) => true,
|
||||
Res::Def(DefKind::TraitAlias, _) => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::Expr(..) => match res {
|
||||
Res::Def(DefKind::Ctor(_, CtorKind::Const), _)
|
||||
| Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
|
||||
| Res::Def(DefKind::Const, _)
|
||||
| Res::Def(DefKind::Static, _)
|
||||
| Res::Local(..)
|
||||
| Res::Def(DefKind::Fn, _)
|
||||
| Res::Def(DefKind::Method, _)
|
||||
| Res::Def(DefKind::AssocConst, _)
|
||||
| Res::SelfCtor(..)
|
||||
| Res::Def(DefKind::ConstParam, _) => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::Pat => match res {
|
||||
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) |
|
||||
Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) |
|
||||
Res::SelfCtor(..) => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::TupleStruct => match res {
|
||||
Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::Struct => match res {
|
||||
Res::Def(DefKind::Struct, _)
|
||||
| Res::Def(DefKind::Union, _)
|
||||
| Res::Def(DefKind::Variant, _)
|
||||
| Res::Def(DefKind::TyAlias, _)
|
||||
| Res::Def(DefKind::AssocTy, _)
|
||||
| Res::SelfTy(..) => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::TraitItem(ns) => match res {
|
||||
Res::Def(DefKind::AssocConst, _)
|
||||
| Res::Def(DefKind::Method, _) if ns == ValueNS => true,
|
||||
Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::Visibility => match res {
|
||||
Res::Def(DefKind::Mod, _) => true,
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn error_code(self, has_unexpected_resolution: bool) -> &'static str {
|
||||
__diagnostic_used!(E0404);
|
||||
__diagnostic_used!(E0405);
|
||||
__diagnostic_used!(E0412);
|
||||
__diagnostic_used!(E0422);
|
||||
__diagnostic_used!(E0423);
|
||||
__diagnostic_used!(E0425);
|
||||
__diagnostic_used!(E0531);
|
||||
__diagnostic_used!(E0532);
|
||||
__diagnostic_used!(E0573);
|
||||
__diagnostic_used!(E0574);
|
||||
__diagnostic_used!(E0575);
|
||||
__diagnostic_used!(E0576);
|
||||
__diagnostic_used!(E0577);
|
||||
__diagnostic_used!(E0578);
|
||||
match (self, has_unexpected_resolution) {
|
||||
(PathSource::Trait(_), true) => "E0404",
|
||||
(PathSource::Trait(_), false) => "E0405",
|
||||
(PathSource::Type, true) => "E0573",
|
||||
(PathSource::Type, false) => "E0412",
|
||||
(PathSource::Struct, true) => "E0574",
|
||||
(PathSource::Struct, false) => "E0422",
|
||||
(PathSource::Expr(..), true) => "E0423",
|
||||
(PathSource::Expr(..), false) => "E0425",
|
||||
(PathSource::Pat, true) | (PathSource::TupleStruct, true) => "E0532",
|
||||
(PathSource::Pat, false) | (PathSource::TupleStruct, false) => "E0531",
|
||||
(PathSource::TraitItem(..), true) => "E0575",
|
||||
(PathSource::TraitItem(..), false) => "E0576",
|
||||
(PathSource::Visibility, true) => "E0577",
|
||||
(PathSource::Visibility, false) => "E0578",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A minimal representation of a path segment. We use this in resolve because
|
||||
// we synthesize 'path segments' which don't have the rest of an AST or HIR
|
||||
// `PathSegment`.
|
||||
@@ -801,255 +302,6 @@ fn visit_mod(
|
||||
}
|
||||
}
|
||||
|
||||
/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
|
||||
impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
||||
fn visit_item(&mut self, item: &'tcx Item) {
|
||||
self.resolve_item(item);
|
||||
}
|
||||
fn visit_arm(&mut self, arm: &'tcx Arm) {
|
||||
self.resolve_arm(arm);
|
||||
}
|
||||
fn visit_block(&mut self, block: &'tcx Block) {
|
||||
self.resolve_block(block);
|
||||
}
|
||||
fn visit_anon_const(&mut self, constant: &'tcx ast::AnonConst) {
|
||||
debug!("visit_anon_const {:?}", constant);
|
||||
self.with_constant_rib(|this| {
|
||||
visit::walk_anon_const(this, constant);
|
||||
});
|
||||
}
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr) {
|
||||
self.resolve_expr(expr, None);
|
||||
}
|
||||
fn visit_local(&mut self, local: &'tcx Local) {
|
||||
self.resolve_local(local);
|
||||
}
|
||||
fn visit_ty(&mut self, ty: &'tcx Ty) {
|
||||
match ty.node {
|
||||
TyKind::Path(ref qself, ref path) => {
|
||||
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
|
||||
}
|
||||
TyKind::ImplicitSelf => {
|
||||
let self_ty = Ident::with_empty_ctxt(kw::SelfUpper);
|
||||
let res = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.id), ty.span)
|
||||
.map_or(Res::Err, |d| d.res());
|
||||
self.record_partial_res(ty.id, PartialRes::new(res));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
visit::walk_ty(self, ty);
|
||||
}
|
||||
fn visit_poly_trait_ref(&mut self,
|
||||
tref: &'tcx ast::PolyTraitRef,
|
||||
m: &'tcx ast::TraitBoundModifier) {
|
||||
self.smart_resolve_path(tref.trait_ref.ref_id, None,
|
||||
&tref.trait_ref.path, PathSource::Trait(AliasPossibility::Maybe));
|
||||
visit::walk_poly_trait_ref(self, tref, m);
|
||||
}
|
||||
fn visit_foreign_item(&mut self, foreign_item: &'tcx ForeignItem) {
|
||||
let generic_params = match foreign_item.node {
|
||||
ForeignItemKind::Fn(_, ref generics) => {
|
||||
HasGenericParams(generics, ItemRibKind)
|
||||
}
|
||||
ForeignItemKind::Static(..) => NoGenericParams,
|
||||
ForeignItemKind::Ty => NoGenericParams,
|
||||
ForeignItemKind::Macro(..) => NoGenericParams,
|
||||
};
|
||||
self.with_generic_param_rib(generic_params, |this| {
|
||||
visit::walk_foreign_item(this, foreign_item);
|
||||
});
|
||||
}
|
||||
fn visit_fn(&mut self,
|
||||
function_kind: FnKind<'tcx>,
|
||||
declaration: &'tcx FnDecl,
|
||||
_: Span,
|
||||
_: NodeId)
|
||||
{
|
||||
debug!("(resolving function) entering function");
|
||||
let rib_kind = match function_kind {
|
||||
FnKind::ItemFn(..) => FnItemRibKind,
|
||||
FnKind::Method(..) | FnKind::Closure(_) => NormalRibKind,
|
||||
};
|
||||
|
||||
// Create a value rib for the function.
|
||||
self.ribs[ValueNS].push(Rib::new(rib_kind));
|
||||
|
||||
// Create a label rib for the function.
|
||||
self.label_ribs.push(Rib::new(rib_kind));
|
||||
|
||||
// Add each argument to the rib.
|
||||
let mut bindings_list = FxHashMap::default();
|
||||
for argument in &declaration.inputs {
|
||||
self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
|
||||
|
||||
self.visit_ty(&argument.ty);
|
||||
|
||||
debug!("(resolving function) recorded argument");
|
||||
}
|
||||
visit::walk_fn_ret_ty(self, &declaration.output);
|
||||
|
||||
// Resolve the function body, potentially inside the body of an async closure
|
||||
match function_kind {
|
||||
FnKind::ItemFn(.., body) |
|
||||
FnKind::Method(.., body) => {
|
||||
self.visit_block(body);
|
||||
}
|
||||
FnKind::Closure(body) => {
|
||||
self.visit_expr(body);
|
||||
}
|
||||
};
|
||||
|
||||
debug!("(resolving function) leaving function");
|
||||
|
||||
self.label_ribs.pop();
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
|
||||
fn visit_generics(&mut self, generics: &'tcx Generics) {
|
||||
// For type parameter defaults, we have to ban access
|
||||
// to following type parameters, as the InternalSubsts can only
|
||||
// provide previous type parameters as they're built. We
|
||||
// put all the parameters on the ban list and then remove
|
||||
// them one by one as they are processed and become available.
|
||||
let mut default_ban_rib = Rib::new(ForwardTyParamBanRibKind);
|
||||
let mut found_default = false;
|
||||
default_ban_rib.bindings.extend(generics.params.iter()
|
||||
.filter_map(|param| match param.kind {
|
||||
GenericParamKind::Const { .. } |
|
||||
GenericParamKind::Lifetime { .. } => None,
|
||||
GenericParamKind::Type { ref default, .. } => {
|
||||
found_default |= default.is_some();
|
||||
if found_default {
|
||||
Some((Ident::with_empty_ctxt(param.ident.name), Res::Err))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
// We also ban access to type parameters for use as the types of const parameters.
|
||||
let mut const_ty_param_ban_rib = Rib::new(TyParamAsConstParamTy);
|
||||
const_ty_param_ban_rib.bindings.extend(generics.params.iter()
|
||||
.filter(|param| {
|
||||
if let GenericParamKind::Type { .. } = param.kind {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.map(|param| (Ident::with_empty_ctxt(param.ident.name), Res::Err)));
|
||||
|
||||
for param in &generics.params {
|
||||
match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => self.visit_generic_param(param),
|
||||
GenericParamKind::Type { ref default, .. } => {
|
||||
for bound in ¶m.bounds {
|
||||
self.visit_param_bound(bound);
|
||||
}
|
||||
|
||||
if let Some(ref ty) = default {
|
||||
self.ribs[TypeNS].push(default_ban_rib);
|
||||
self.visit_ty(ty);
|
||||
default_ban_rib = self.ribs[TypeNS].pop().unwrap();
|
||||
}
|
||||
|
||||
// Allow all following defaults to refer to this type parameter.
|
||||
default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name));
|
||||
}
|
||||
GenericParamKind::Const { ref ty } => {
|
||||
self.ribs[TypeNS].push(const_ty_param_ban_rib);
|
||||
|
||||
for bound in ¶m.bounds {
|
||||
self.visit_param_bound(bound);
|
||||
}
|
||||
|
||||
self.visit_ty(ty);
|
||||
|
||||
const_ty_param_ban_rib = self.ribs[TypeNS].pop().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
for p in &generics.where_clause.predicates {
|
||||
self.visit_where_predicate(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum GenericParameters<'a, 'b> {
|
||||
NoGenericParams,
|
||||
HasGenericParams(// Type parameters.
|
||||
&'b Generics,
|
||||
|
||||
// The kind of the rib used for type parameters.
|
||||
RibKind<'a>),
|
||||
}
|
||||
|
||||
/// The rib kind restricts certain accesses,
|
||||
/// e.g. to a `Res::Local` of an outer item.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum RibKind<'a> {
|
||||
/// No restriction needs to be applied.
|
||||
NormalRibKind,
|
||||
|
||||
/// We passed through an impl or trait and are now in one of its
|
||||
/// methods or associated types. Allow references to ty params that impl or trait
|
||||
/// binds. Disallow any other upvars (including other ty params that are
|
||||
/// upvars).
|
||||
AssocItemRibKind,
|
||||
|
||||
/// We passed through a function definition. Disallow upvars.
|
||||
/// Permit only those const parameters that are specified in the function's generics.
|
||||
FnItemRibKind,
|
||||
|
||||
/// We passed through an item scope. Disallow upvars.
|
||||
ItemRibKind,
|
||||
|
||||
/// We're in a constant item. Can't refer to dynamic stuff.
|
||||
ConstantItemRibKind,
|
||||
|
||||
/// We passed through a module.
|
||||
ModuleRibKind(Module<'a>),
|
||||
|
||||
/// We passed through a `macro_rules!` statement
|
||||
MacroDefinition(DefId),
|
||||
|
||||
/// All bindings in this rib are type parameters that can't be used
|
||||
/// from the default of a type parameter because they're not declared
|
||||
/// before said type parameter. Also see the `visit_generics` override.
|
||||
ForwardTyParamBanRibKind,
|
||||
|
||||
/// We forbid the use of type parameters as the types of const parameters.
|
||||
TyParamAsConstParamTy,
|
||||
}
|
||||
|
||||
/// A single local scope.
|
||||
///
|
||||
/// A rib represents a scope names can live in. Note that these appear in many places, not just
|
||||
/// around braces. At any place where the list of accessible names (of the given namespace)
|
||||
/// changes or a new restrictions on the name accessibility are introduced, a new rib is put onto a
|
||||
/// stack. This may be, for example, a `let` statement (because it introduces variables), a macro,
|
||||
/// etc.
|
||||
///
|
||||
/// Different [rib kinds](enum.RibKind) are transparent for different names.
|
||||
///
|
||||
/// The resolution keeps a separate stack of ribs as it traverses the AST for each namespace. When
|
||||
/// resolving, the name is looked up from inside out.
|
||||
#[derive(Debug)]
|
||||
struct Rib<'a, R = Res> {
|
||||
bindings: FxHashMap<Ident, R>,
|
||||
kind: RibKind<'a>,
|
||||
}
|
||||
|
||||
impl<'a, R> Rib<'a, R> {
|
||||
fn new(kind: RibKind<'a>) -> Rib<'a, R> {
|
||||
Rib {
|
||||
bindings: Default::default(),
|
||||
kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An intermediate resolution result.
|
||||
///
|
||||
/// This refers to the thing referred by a name. The difference between `Res` and `Item` is that
|
||||
@@ -1587,28 +839,6 @@ pub struct Resolver<'a> {
|
||||
/// All non-determined imports.
|
||||
indeterminate_imports: Vec<&'a ImportDirective<'a>>,
|
||||
|
||||
/// The module that represents the current item scope.
|
||||
current_module: Module<'a>,
|
||||
|
||||
/// The current set of local scopes for types and values.
|
||||
/// FIXME #4948: Reuse ribs to avoid allocation.
|
||||
ribs: PerNS<Vec<Rib<'a>>>,
|
||||
|
||||
/// The current set of local scopes, for labels.
|
||||
label_ribs: Vec<Rib<'a, NodeId>>,
|
||||
|
||||
/// The trait that the current context can refer to.
|
||||
current_trait_ref: Option<(Module<'a>, TraitRef)>,
|
||||
|
||||
/// The current trait's associated types' ident, used for diagnostic suggestions.
|
||||
current_trait_assoc_types: Vec<Ident>,
|
||||
|
||||
/// The current self type if inside an impl (used for better errors).
|
||||
current_self_type: Option<Ty>,
|
||||
|
||||
/// The current self item if inside an ADT (used for better errors).
|
||||
current_self_item: Option<NodeId>,
|
||||
|
||||
/// FIXME: Refactor things so that these fields are passed through arguments and not resolver.
|
||||
/// We are resolving a last import segment during import validation.
|
||||
last_import_segment: bool,
|
||||
@@ -1655,10 +885,6 @@ pub struct Resolver<'a> {
|
||||
pub maybe_unused_trait_imports: NodeSet,
|
||||
pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
|
||||
|
||||
/// A list of labels as of yet unused. Labels will be removed from this map when
|
||||
/// they are used (in a `break` or `continue` statement)
|
||||
pub unused_labels: FxHashMap<NodeId, Span>,
|
||||
|
||||
/// Privacy errors are delayed until the end in order to deduplicate them.
|
||||
privacy_errors: Vec<PrivacyError<'a>>,
|
||||
/// Ambiguity errors are delayed for deduplication.
|
||||
@@ -1703,9 +929,6 @@ pub struct Resolver<'a> {
|
||||
/// it's not used during normal resolution, only for better error reporting.
|
||||
struct_constructors: DefIdMap<(Res, ty::Visibility)>,
|
||||
|
||||
/// Only used for better errors on `fn(): fn()`.
|
||||
current_type_ascription: Vec<Span>,
|
||||
|
||||
injected_crate: Option<Module<'a>>,
|
||||
|
||||
/// Features enabled for this crate.
|
||||
@@ -1766,26 +989,12 @@ fn parent(self, id: DefId) -> Option<DefId> {
|
||||
/// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that
|
||||
/// the resolver is no longer needed as all the relevant information is inline.
|
||||
impl<'a> hir::lowering::Resolver for Resolver<'a> {
|
||||
fn resolve_ast_path(
|
||||
&mut self,
|
||||
path: &ast::Path,
|
||||
is_value: bool,
|
||||
) -> Res {
|
||||
match self.resolve_ast_path_inner(path, is_value) {
|
||||
Ok(r) => r,
|
||||
Err((span, error)) => {
|
||||
resolve_error(self, span, error);
|
||||
Res::Err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_str_path(
|
||||
&mut self,
|
||||
span: Span,
|
||||
crate_root: Option<Symbol>,
|
||||
components: &[Symbol],
|
||||
is_value: bool
|
||||
ns: Namespace,
|
||||
) -> (ast::Path, Res) {
|
||||
let root = if crate_root.is_some() {
|
||||
kw::PathRoot
|
||||
@@ -1804,7 +1013,14 @@ fn resolve_str_path(
|
||||
segments,
|
||||
};
|
||||
|
||||
let res = self.resolve_ast_path(&path, is_value);
|
||||
let parent_scope = &self.dummy_parent_scope();
|
||||
let res = match self.resolve_ast_path(&path, ns, parent_scope) {
|
||||
Ok(res) => res,
|
||||
Err((span, error)) => {
|
||||
self.report_error(span, error);
|
||||
Res::Err
|
||||
}
|
||||
};
|
||||
(path, res)
|
||||
}
|
||||
|
||||
@@ -1831,76 +1047,6 @@ fn has_derives(&self, node_id: NodeId, derives: SpecialDerives) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Resolver<'a> {
|
||||
/// Rustdoc uses this to resolve things in a recoverable way. `ResolutionError<'a>`
|
||||
/// isn't something that can be returned because it can't be made to live that long,
|
||||
/// and also it's a private type. Fortunately rustdoc doesn't need to know the error,
|
||||
/// just that an error occurred.
|
||||
pub fn resolve_str_path_error(&mut self, span: Span, path_str: &str, is_value: bool)
|
||||
-> Result<(ast::Path, Res), ()> {
|
||||
let path = if path_str.starts_with("::") {
|
||||
ast::Path {
|
||||
span,
|
||||
segments: iter::once(Ident::with_empty_ctxt(kw::PathRoot))
|
||||
.chain({
|
||||
path_str.split("::").skip(1).map(Ident::from_str)
|
||||
})
|
||||
.map(|i| self.new_ast_path_segment(i))
|
||||
.collect(),
|
||||
}
|
||||
} else {
|
||||
ast::Path {
|
||||
span,
|
||||
segments: path_str
|
||||
.split("::")
|
||||
.map(Ident::from_str)
|
||||
.map(|i| self.new_ast_path_segment(i))
|
||||
.collect(),
|
||||
}
|
||||
};
|
||||
let res = self.resolve_ast_path_inner(&path, is_value).map_err(|_| ())?;
|
||||
Ok((path, res))
|
||||
}
|
||||
|
||||
/// Like `resolve_ast_path`, but takes a callback in case there was an error.
|
||||
fn resolve_ast_path_inner(
|
||||
&mut self,
|
||||
path: &ast::Path,
|
||||
is_value: bool,
|
||||
) -> Result<Res, (Span, ResolutionError<'a>)> {
|
||||
let namespace = if is_value { ValueNS } else { TypeNS };
|
||||
let span = path.span;
|
||||
let path = Segment::from_path(&path);
|
||||
// FIXME(Manishearth): intra-doc links won't get warned of epoch changes.
|
||||
match self.resolve_path_without_parent_scope(&path, Some(namespace), true,
|
||||
span, CrateLint::No) {
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
|
||||
Ok(module.res().unwrap()),
|
||||
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 =>
|
||||
Ok(path_res.base_res()),
|
||||
PathResult::NonModule(..) => {
|
||||
Err((span, ResolutionError::FailedToResolve {
|
||||
label: String::from("type-relative paths are not supported in this context"),
|
||||
suggestion: None,
|
||||
}))
|
||||
}
|
||||
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
|
||||
PathResult::Failed { span, label, suggestion, .. } => {
|
||||
Err((span, ResolutionError::FailedToResolve {
|
||||
label,
|
||||
suggestion,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn new_ast_path_segment(&self, ident: Ident) -> ast::PathSegment {
|
||||
let mut seg = ast::PathSegment::from_ident(ident);
|
||||
seg.id = self.session.next_node_id();
|
||||
seg
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Resolver<'a> {
|
||||
pub fn new(session: &'a Session,
|
||||
cstore: &'a CStore,
|
||||
@@ -1969,18 +1115,6 @@ pub fn new(session: &'a Session,
|
||||
determined_imports: Vec::new(),
|
||||
indeterminate_imports: Vec::new(),
|
||||
|
||||
current_module: graph_root,
|
||||
ribs: PerNS {
|
||||
value_ns: vec![Rib::new(ModuleRibKind(graph_root))],
|
||||
type_ns: vec![Rib::new(ModuleRibKind(graph_root))],
|
||||
macro_ns: vec![Rib::new(ModuleRibKind(graph_root))],
|
||||
},
|
||||
label_ribs: Vec::new(),
|
||||
|
||||
current_trait_ref: None,
|
||||
current_trait_assoc_types: Vec::new(),
|
||||
current_self_type: None,
|
||||
current_self_item: None,
|
||||
last_import_segment: false,
|
||||
blacklisted_binding: None,
|
||||
|
||||
@@ -2002,8 +1136,6 @@ pub fn new(session: &'a Session,
|
||||
maybe_unused_trait_imports: Default::default(),
|
||||
maybe_unused_extern_crates: Vec::new(),
|
||||
|
||||
unused_labels: FxHashMap::default(),
|
||||
|
||||
privacy_errors: Vec::new(),
|
||||
ambiguity_errors: Vec::new(),
|
||||
use_injections: Vec::new(),
|
||||
@@ -2036,7 +1168,6 @@ pub fn new(session: &'a Session,
|
||||
unused_macros: Default::default(),
|
||||
proc_macro_stubs: Default::default(),
|
||||
special_derives: Default::default(),
|
||||
current_type_ascription: Vec::new(),
|
||||
injected_crate: None,
|
||||
active_features:
|
||||
features.declared_lib_features.iter().map(|(feat, ..)| *feat)
|
||||
@@ -2088,13 +1219,11 @@ fn has_derives(&self, expn_id: ExpnId, markers: SpecialDerives) -> bool {
|
||||
|
||||
/// Entry point to crate resolution.
|
||||
pub fn resolve_crate(&mut self, krate: &Crate) {
|
||||
ImportResolver { resolver: self }.finalize_imports();
|
||||
self.current_module = self.graph_root;
|
||||
self.finalize_current_module_macro_resolutions();
|
||||
ImportResolver { r: self }.finalize_imports();
|
||||
|
||||
visit::walk_crate(self, krate);
|
||||
self.late_resolve_crate(krate);
|
||||
|
||||
check_unused::check_crate(self, krate);
|
||||
self.check_unused(krate);
|
||||
self.report_errors(krate);
|
||||
self.crate_loader.postprocess(krate);
|
||||
}
|
||||
@@ -2203,10 +1332,9 @@ fn visit_scopes<T>(
|
||||
|
||||
let rust_2015 = ident.span.rust_2015();
|
||||
let (ns, is_absolute_path) = match scope_set {
|
||||
ScopeSet::Import(ns) => (ns, false),
|
||||
ScopeSet::All(ns, _) => (ns, false),
|
||||
ScopeSet::AbsolutePath(ns) => (ns, true),
|
||||
ScopeSet::Macro(_) => (MacroNS, false),
|
||||
ScopeSet::Module => (TypeNS, false),
|
||||
};
|
||||
let mut scope = match ns {
|
||||
_ if is_absolute_path => Scope::CrateRoot,
|
||||
@@ -2308,8 +1436,10 @@ fn visit_scopes<T>(
|
||||
fn resolve_ident_in_lexical_scope(&mut self,
|
||||
mut ident: Ident,
|
||||
ns: Namespace,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
record_used_id: Option<NodeId>,
|
||||
path_span: Span)
|
||||
path_span: Span,
|
||||
ribs: &[Rib<'a>])
|
||||
-> Option<LexicalScopeBinding<'a>> {
|
||||
assert!(ns == TypeNS || ns == ValueNS);
|
||||
if ident.name == kw::Invalid {
|
||||
@@ -2331,23 +1461,23 @@ fn resolve_ident_in_lexical_scope(&mut self,
|
||||
// Walk backwards up the ribs in scope.
|
||||
let record_used = record_used_id.is_some();
|
||||
let mut module = self.graph_root;
|
||||
for i in (0 .. self.ribs[ns].len()).rev() {
|
||||
debug!("walk rib\n{:?}", self.ribs[ns][i].bindings);
|
||||
for i in (0 .. ribs.len()).rev() {
|
||||
debug!("walk rib\n{:?}", ribs[i].bindings);
|
||||
// Use the rib kind to determine whether we are resolving parameters
|
||||
// (modern hygiene) or local variables (legacy hygiene).
|
||||
let rib_ident = if let AssocItemRibKind | ItemRibKind = self.ribs[ns][i].kind {
|
||||
let rib_ident = if let AssocItemRibKind | ItemRibKind = ribs[i].kind {
|
||||
modern_ident
|
||||
} else {
|
||||
ident
|
||||
};
|
||||
if let Some(res) = self.ribs[ns][i].bindings.get(&rib_ident).cloned() {
|
||||
if let Some(res) = ribs[i].bindings.get(&rib_ident).cloned() {
|
||||
// The ident resolves to a type parameter or local variable.
|
||||
return Some(LexicalScopeBinding::Res(
|
||||
self.validate_res_from_ribs(ns, i, res, record_used, path_span),
|
||||
self.validate_res_from_ribs(i, res, record_used, path_span, ribs),
|
||||
));
|
||||
}
|
||||
|
||||
module = match self.ribs[ns][i].kind {
|
||||
module = match ribs[i].kind {
|
||||
ModuleRibKind(module) => module,
|
||||
MacroDefinition(def) if def == self.macro_def(ident.span.ctxt()) => {
|
||||
// If an invocation of this macro created `ident`, give up on `ident`
|
||||
@@ -2358,10 +1488,12 @@ fn resolve_ident_in_lexical_scope(&mut self,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
|
||||
let item = self.resolve_ident_in_module_unadjusted(
|
||||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
ns,
|
||||
parent_scope,
|
||||
record_used,
|
||||
path_span,
|
||||
);
|
||||
@@ -2386,16 +1518,15 @@ fn resolve_ident_in_lexical_scope(&mut self,
|
||||
self.hygienic_lexical_parent(module, &mut ident.span)
|
||||
};
|
||||
module = unwrap_or!(opt_module, break);
|
||||
let orig_current_module = self.current_module;
|
||||
self.current_module = module; // Lexical resolutions can never be a privacy error.
|
||||
let adjusted_parent_scope = &ParentScope { module, ..parent_scope.clone() };
|
||||
let result = self.resolve_ident_in_module_unadjusted(
|
||||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
ns,
|
||||
adjusted_parent_scope,
|
||||
record_used,
|
||||
path_span,
|
||||
);
|
||||
self.current_module = orig_current_module;
|
||||
|
||||
match result {
|
||||
Ok(binding) => {
|
||||
@@ -2433,6 +1564,7 @@ fn resolve_ident_in_lexical_scope(&mut self,
|
||||
ModuleOrUniformRoot::Module(prelude),
|
||||
ident,
|
||||
ns,
|
||||
parent_scope,
|
||||
false,
|
||||
path_span,
|
||||
) {
|
||||
@@ -2498,7 +1630,7 @@ fn resolve_ident_in_module(
|
||||
module: ModuleOrUniformRoot<'a>,
|
||||
ident: Ident,
|
||||
ns: Namespace,
|
||||
parent_scope: Option<&ParentScope<'a>>,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
record_used: bool,
|
||||
path_span: Span
|
||||
) -> Result<&'a NameBinding<'a>, Determinacy> {
|
||||
@@ -2512,15 +1644,18 @@ fn resolve_ident_in_module_ext(
|
||||
module: ModuleOrUniformRoot<'a>,
|
||||
mut ident: Ident,
|
||||
ns: Namespace,
|
||||
parent_scope: Option<&ParentScope<'a>>,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
record_used: bool,
|
||||
path_span: Span
|
||||
) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> {
|
||||
let orig_current_module = self.current_module;
|
||||
let tmp_parent_scope;
|
||||
let mut adjusted_parent_scope = parent_scope;
|
||||
match module {
|
||||
ModuleOrUniformRoot::Module(module) => {
|
||||
if let Some(def) = ident.span.modernize_and_adjust(module.expansion) {
|
||||
self.current_module = self.macro_def_scope(def);
|
||||
ModuleOrUniformRoot::Module(m) => {
|
||||
if let Some(def) = ident.span.modernize_and_adjust(m.expansion) {
|
||||
tmp_parent_scope =
|
||||
ParentScope { module: self.macro_def_scope(def), ..parent_scope.clone() };
|
||||
adjusted_parent_scope = &tmp_parent_scope;
|
||||
}
|
||||
}
|
||||
ModuleOrUniformRoot::ExternPrelude => {
|
||||
@@ -2532,9 +1667,8 @@ fn resolve_ident_in_module_ext(
|
||||
}
|
||||
}
|
||||
let result = self.resolve_ident_in_module_unadjusted_ext(
|
||||
module, ident, ns, parent_scope, false, record_used, path_span,
|
||||
module, ident, ns, adjusted_parent_scope, false, record_used, path_span,
|
||||
);
|
||||
self.current_module = orig_current_module;
|
||||
result
|
||||
}
|
||||
|
||||
@@ -2588,1279 +1722,6 @@ fn resolve_self(&mut self, ctxt: &mut SyntaxContext, module: Module<'a>) -> Modu
|
||||
module
|
||||
}
|
||||
|
||||
// AST resolution
|
||||
//
|
||||
// We maintain a list of value ribs and type ribs.
|
||||
//
|
||||
// Simultaneously, we keep track of the current position in the module
|
||||
// graph in the `current_module` pointer. When we go to resolve a name in
|
||||
// the value or type namespaces, we first look through all the ribs and
|
||||
// then query the module graph. When we resolve a name in the module
|
||||
// namespace, we can skip all the ribs (since nested modules are not
|
||||
// allowed within blocks in Rust) and jump straight to the current module
|
||||
// graph node.
|
||||
//
|
||||
// Named implementations are handled separately. When we find a method
|
||||
// call, we consult the module node to find all of the implementations in
|
||||
// scope. This information is lazily cached in the module node. We then
|
||||
// generate a fake "implementation scope" containing all the
|
||||
// implementations thus found, for compatibility with old resolve pass.
|
||||
|
||||
pub fn with_scope<F, T>(&mut self, id: NodeId, f: F) -> T
|
||||
where F: FnOnce(&mut Resolver<'_>) -> T
|
||||
{
|
||||
let id = self.definitions.local_def_id(id);
|
||||
let module = self.module_map.get(&id).cloned(); // clones a reference
|
||||
if let Some(module) = module {
|
||||
// Move down in the graph.
|
||||
let orig_module = replace(&mut self.current_module, module);
|
||||
self.ribs[ValueNS].push(Rib::new(ModuleRibKind(module)));
|
||||
self.ribs[TypeNS].push(Rib::new(ModuleRibKind(module)));
|
||||
|
||||
self.finalize_current_module_macro_resolutions();
|
||||
let ret = f(self);
|
||||
|
||||
self.current_module = orig_module;
|
||||
self.ribs[ValueNS].pop();
|
||||
self.ribs[TypeNS].pop();
|
||||
ret
|
||||
} else {
|
||||
f(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Searches the current set of local scopes for labels. Returns the first non-`None` label that
|
||||
/// is returned by the given predicate function
|
||||
///
|
||||
/// Stops after meeting a closure.
|
||||
fn search_label<P, R>(&self, mut ident: Ident, pred: P) -> Option<R>
|
||||
where P: Fn(&Rib<'_, NodeId>, Ident) -> Option<R>
|
||||
{
|
||||
for rib in self.label_ribs.iter().rev() {
|
||||
match rib.kind {
|
||||
NormalRibKind => {}
|
||||
// If an invocation of this macro created `ident`, give up on `ident`
|
||||
// and switch to `ident`'s source from the macro definition.
|
||||
MacroDefinition(def) => {
|
||||
if def == self.macro_def(ident.span.ctxt()) {
|
||||
ident.span.remove_mark();
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Do not resolve labels across function boundary
|
||||
return None;
|
||||
}
|
||||
}
|
||||
let r = pred(rib, ident);
|
||||
if r.is_some() {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn resolve_adt(&mut self, item: &Item, generics: &Generics) {
|
||||
debug!("resolve_adt");
|
||||
self.with_current_self_item(item, |this| {
|
||||
this.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
|
||||
let item_def_id = this.definitions.local_def_id(item.id);
|
||||
this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| {
|
||||
visit::walk_item(this, item);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn future_proof_import(&mut self, use_tree: &ast::UseTree) {
|
||||
let segments = &use_tree.prefix.segments;
|
||||
if !segments.is_empty() {
|
||||
let ident = segments[0].ident;
|
||||
if ident.is_path_segment_keyword() || ident.span.rust_2015() {
|
||||
return;
|
||||
}
|
||||
|
||||
let nss = match use_tree.kind {
|
||||
ast::UseTreeKind::Simple(..) if segments.len() == 1 => &[TypeNS, ValueNS][..],
|
||||
_ => &[TypeNS],
|
||||
};
|
||||
let report_error = |this: &Self, ns| {
|
||||
let what = if ns == TypeNS { "type parameters" } else { "local variables" };
|
||||
this.session.span_err(ident.span, &format!("imports cannot refer to {}", what));
|
||||
};
|
||||
|
||||
for &ns in nss {
|
||||
match self.resolve_ident_in_lexical_scope(ident, ns, None, use_tree.prefix.span) {
|
||||
Some(LexicalScopeBinding::Res(..)) => {
|
||||
report_error(self, ns);
|
||||
}
|
||||
Some(LexicalScopeBinding::Item(binding)) => {
|
||||
let orig_blacklisted_binding =
|
||||
mem::replace(&mut self.blacklisted_binding, Some(binding));
|
||||
if let Some(LexicalScopeBinding::Res(..)) =
|
||||
self.resolve_ident_in_lexical_scope(ident, ns, None,
|
||||
use_tree.prefix.span) {
|
||||
report_error(self, ns);
|
||||
}
|
||||
self.blacklisted_binding = orig_blacklisted_binding;
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
} else if let ast::UseTreeKind::Nested(use_trees) = &use_tree.kind {
|
||||
for (use_tree, _) in use_trees {
|
||||
self.future_proof_import(use_tree);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_item(&mut self, item: &Item) {
|
||||
let name = item.ident.name;
|
||||
debug!("(resolving item) resolving {} ({:?})", name, item.node);
|
||||
|
||||
match item.node {
|
||||
ItemKind::TyAlias(_, ref generics) |
|
||||
ItemKind::OpaqueTy(_, ref generics) |
|
||||
ItemKind::Fn(_, _, ref generics, _) => {
|
||||
self.with_generic_param_rib(
|
||||
HasGenericParams(generics, ItemRibKind),
|
||||
|this| visit::walk_item(this, item)
|
||||
);
|
||||
}
|
||||
|
||||
ItemKind::Enum(_, ref generics) |
|
||||
ItemKind::Struct(_, ref generics) |
|
||||
ItemKind::Union(_, ref generics) => {
|
||||
self.resolve_adt(item, generics);
|
||||
}
|
||||
|
||||
ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
|
||||
self.resolve_implementation(generics,
|
||||
opt_trait_ref,
|
||||
&self_type,
|
||||
item.id,
|
||||
impl_items),
|
||||
|
||||
ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => {
|
||||
// Create a new rib for the trait-wide type parameters.
|
||||
self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
|
||||
let local_def_id = this.definitions.local_def_id(item.id);
|
||||
this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
|
||||
this.visit_generics(generics);
|
||||
walk_list!(this, visit_param_bound, bounds);
|
||||
|
||||
for trait_item in trait_items {
|
||||
this.with_trait_items(trait_items, |this| {
|
||||
let generic_params = HasGenericParams(
|
||||
&trait_item.generics,
|
||||
AssocItemRibKind,
|
||||
);
|
||||
this.with_generic_param_rib(generic_params, |this| {
|
||||
match trait_item.node {
|
||||
TraitItemKind::Const(ref ty, ref default) => {
|
||||
this.visit_ty(ty);
|
||||
|
||||
// Only impose the restrictions of
|
||||
// ConstRibKind for an actual constant
|
||||
// expression in a provided default.
|
||||
if let Some(ref expr) = *default{
|
||||
this.with_constant_rib(|this| {
|
||||
this.visit_expr(expr);
|
||||
});
|
||||
}
|
||||
}
|
||||
TraitItemKind::Method(_, _) => {
|
||||
visit::walk_trait_item(this, trait_item)
|
||||
}
|
||||
TraitItemKind::Type(..) => {
|
||||
visit::walk_trait_item(this, trait_item)
|
||||
}
|
||||
TraitItemKind::Macro(_) => {
|
||||
panic!("unexpanded macro in resolve!")
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ItemKind::TraitAlias(ref generics, ref bounds) => {
|
||||
// Create a new rib for the trait-wide type parameters.
|
||||
self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
|
||||
let local_def_id = this.definitions.local_def_id(item.id);
|
||||
this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
|
||||
this.visit_generics(generics);
|
||||
walk_list!(this, visit_param_bound, bounds);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ItemKind::Mod(_) | ItemKind::ForeignMod(_) => {
|
||||
self.with_scope(item.id, |this| {
|
||||
visit::walk_item(this, item);
|
||||
});
|
||||
}
|
||||
|
||||
ItemKind::Static(ref ty, _, ref expr) |
|
||||
ItemKind::Const(ref ty, ref expr) => {
|
||||
debug!("resolve_item ItemKind::Const");
|
||||
self.with_item_rib(|this| {
|
||||
this.visit_ty(ty);
|
||||
this.with_constant_rib(|this| {
|
||||
this.visit_expr(expr);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ItemKind::Use(ref use_tree) => {
|
||||
self.future_proof_import(use_tree);
|
||||
}
|
||||
|
||||
ItemKind::ExternCrate(..) |
|
||||
ItemKind::MacroDef(..) | ItemKind::GlobalAsm(..) => {
|
||||
// do nothing, these are just around to be encoded
|
||||
}
|
||||
|
||||
ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"),
|
||||
}
|
||||
}
|
||||
|
||||
fn with_generic_param_rib<'b, F>(&'b mut self, generic_params: GenericParameters<'a, 'b>, f: F)
|
||||
where F: FnOnce(&mut Resolver<'_>)
|
||||
{
|
||||
debug!("with_generic_param_rib");
|
||||
match generic_params {
|
||||
HasGenericParams(generics, rib_kind) => {
|
||||
let mut function_type_rib = Rib::new(rib_kind);
|
||||
let mut function_value_rib = Rib::new(rib_kind);
|
||||
let mut seen_bindings = FxHashMap::default();
|
||||
for param in &generics.params {
|
||||
match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => {}
|
||||
GenericParamKind::Type { .. } => {
|
||||
let ident = param.ident.modern();
|
||||
debug!("with_generic_param_rib: {}", param.id);
|
||||
|
||||
if seen_bindings.contains_key(&ident) {
|
||||
let span = seen_bindings.get(&ident).unwrap();
|
||||
let err = ResolutionError::NameAlreadyUsedInParameterList(
|
||||
ident.name,
|
||||
*span,
|
||||
);
|
||||
resolve_error(self, param.ident.span, err);
|
||||
}
|
||||
seen_bindings.entry(ident).or_insert(param.ident.span);
|
||||
|
||||
// Plain insert (no renaming).
|
||||
let res = Res::Def(
|
||||
DefKind::TyParam,
|
||||
self.definitions.local_def_id(param.id),
|
||||
);
|
||||
function_type_rib.bindings.insert(ident, res);
|
||||
self.record_partial_res(param.id, PartialRes::new(res));
|
||||
}
|
||||
GenericParamKind::Const { .. } => {
|
||||
let ident = param.ident.modern();
|
||||
debug!("with_generic_param_rib: {}", param.id);
|
||||
|
||||
if seen_bindings.contains_key(&ident) {
|
||||
let span = seen_bindings.get(&ident).unwrap();
|
||||
let err = ResolutionError::NameAlreadyUsedInParameterList(
|
||||
ident.name,
|
||||
*span,
|
||||
);
|
||||
resolve_error(self, param.ident.span, err);
|
||||
}
|
||||
seen_bindings.entry(ident).or_insert(param.ident.span);
|
||||
|
||||
let res = Res::Def(
|
||||
DefKind::ConstParam,
|
||||
self.definitions.local_def_id(param.id),
|
||||
);
|
||||
function_value_rib.bindings.insert(ident, res);
|
||||
self.record_partial_res(param.id, PartialRes::new(res));
|
||||
}
|
||||
}
|
||||
}
|
||||
self.ribs[ValueNS].push(function_value_rib);
|
||||
self.ribs[TypeNS].push(function_type_rib);
|
||||
}
|
||||
|
||||
NoGenericParams => {
|
||||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
|
||||
f(self);
|
||||
|
||||
if let HasGenericParams(..) = generic_params {
|
||||
self.ribs[TypeNS].pop();
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
}
|
||||
|
||||
fn with_label_rib<F>(&mut self, f: F)
|
||||
where F: FnOnce(&mut Resolver<'_>)
|
||||
{
|
||||
self.label_ribs.push(Rib::new(NormalRibKind));
|
||||
f(self);
|
||||
self.label_ribs.pop();
|
||||
}
|
||||
|
||||
fn with_item_rib<F>(&mut self, f: F)
|
||||
where F: FnOnce(&mut Resolver<'_>)
|
||||
{
|
||||
self.ribs[ValueNS].push(Rib::new(ItemRibKind));
|
||||
self.ribs[TypeNS].push(Rib::new(ItemRibKind));
|
||||
f(self);
|
||||
self.ribs[TypeNS].pop();
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
|
||||
fn with_constant_rib<F>(&mut self, f: F)
|
||||
where F: FnOnce(&mut Resolver<'_>)
|
||||
{
|
||||
debug!("with_constant_rib");
|
||||
self.ribs[ValueNS].push(Rib::new(ConstantItemRibKind));
|
||||
self.label_ribs.push(Rib::new(ConstantItemRibKind));
|
||||
f(self);
|
||||
self.label_ribs.pop();
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
|
||||
fn with_current_self_type<T, F>(&mut self, self_type: &Ty, f: F) -> T
|
||||
where F: FnOnce(&mut Resolver<'_>) -> T
|
||||
{
|
||||
// Handle nested impls (inside fn bodies)
|
||||
let previous_value = replace(&mut self.current_self_type, Some(self_type.clone()));
|
||||
let result = f(self);
|
||||
self.current_self_type = previous_value;
|
||||
result
|
||||
}
|
||||
|
||||
fn with_current_self_item<T, F>(&mut self, self_item: &Item, f: F) -> T
|
||||
where F: FnOnce(&mut Resolver<'_>) -> T
|
||||
{
|
||||
let previous_value = replace(&mut self.current_self_item, Some(self_item.id));
|
||||
let result = f(self);
|
||||
self.current_self_item = previous_value;
|
||||
result
|
||||
}
|
||||
|
||||
/// When evaluating a `trait` use its associated types' idents for suggestionsa in E0412.
|
||||
fn with_trait_items<T, F>(&mut self, trait_items: &Vec<TraitItem>, f: F) -> T
|
||||
where F: FnOnce(&mut Resolver<'_>) -> T
|
||||
{
|
||||
let trait_assoc_types = replace(
|
||||
&mut self.current_trait_assoc_types,
|
||||
trait_items.iter().filter_map(|item| match &item.node {
|
||||
TraitItemKind::Type(bounds, _) if bounds.len() == 0 => Some(item.ident),
|
||||
_ => None,
|
||||
}).collect(),
|
||||
);
|
||||
let result = f(self);
|
||||
self.current_trait_assoc_types = trait_assoc_types;
|
||||
result
|
||||
}
|
||||
|
||||
/// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`).
|
||||
fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T
|
||||
where F: FnOnce(&mut Resolver<'_>, Option<DefId>) -> T
|
||||
{
|
||||
let mut new_val = None;
|
||||
let mut new_id = None;
|
||||
if let Some(trait_ref) = opt_trait_ref {
|
||||
let path: Vec<_> = Segment::from_path(&trait_ref.path);
|
||||
let res = self.smart_resolve_path_fragment(
|
||||
trait_ref.ref_id,
|
||||
None,
|
||||
&path,
|
||||
trait_ref.path.span,
|
||||
PathSource::Trait(AliasPossibility::No),
|
||||
CrateLint::SimplePath(trait_ref.ref_id),
|
||||
).base_res();
|
||||
if res != Res::Err {
|
||||
new_id = Some(res.def_id());
|
||||
let span = trait_ref.path.span;
|
||||
if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
|
||||
self.resolve_path_without_parent_scope(
|
||||
&path,
|
||||
Some(TypeNS),
|
||||
false,
|
||||
span,
|
||||
CrateLint::SimplePath(trait_ref.ref_id),
|
||||
)
|
||||
{
|
||||
new_val = Some((module, trait_ref.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
let original_trait_ref = replace(&mut self.current_trait_ref, new_val);
|
||||
let result = f(self, new_id);
|
||||
self.current_trait_ref = original_trait_ref;
|
||||
result
|
||||
}
|
||||
|
||||
fn with_self_rib<F>(&mut self, self_res: Res, f: F)
|
||||
where F: FnOnce(&mut Resolver<'_>)
|
||||
{
|
||||
let mut self_type_rib = Rib::new(NormalRibKind);
|
||||
|
||||
// Plain insert (no renaming, since types are not currently hygienic)
|
||||
self_type_rib.bindings.insert(Ident::with_empty_ctxt(kw::SelfUpper), self_res);
|
||||
self.ribs[TypeNS].push(self_type_rib);
|
||||
f(self);
|
||||
self.ribs[TypeNS].pop();
|
||||
}
|
||||
|
||||
fn with_self_struct_ctor_rib<F>(&mut self, impl_id: DefId, f: F)
|
||||
where F: FnOnce(&mut Resolver<'_>)
|
||||
{
|
||||
let self_res = Res::SelfCtor(impl_id);
|
||||
let mut self_type_rib = Rib::new(NormalRibKind);
|
||||
self_type_rib.bindings.insert(Ident::with_empty_ctxt(kw::SelfUpper), self_res);
|
||||
self.ribs[ValueNS].push(self_type_rib);
|
||||
f(self);
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
|
||||
fn resolve_implementation(&mut self,
|
||||
generics: &Generics,
|
||||
opt_trait_reference: &Option<TraitRef>,
|
||||
self_type: &Ty,
|
||||
item_id: NodeId,
|
||||
impl_items: &[ImplItem]) {
|
||||
debug!("resolve_implementation");
|
||||
// If applicable, create a rib for the type parameters.
|
||||
self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
|
||||
// Dummy self type for better errors if `Self` is used in the trait path.
|
||||
this.with_self_rib(Res::SelfTy(None, None), |this| {
|
||||
// Resolve the trait reference, if necessary.
|
||||
this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
|
||||
let item_def_id = this.definitions.local_def_id(item_id);
|
||||
this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| {
|
||||
if let Some(trait_ref) = opt_trait_reference.as_ref() {
|
||||
// Resolve type arguments in the trait path.
|
||||
visit::walk_trait_ref(this, trait_ref);
|
||||
}
|
||||
// Resolve the self type.
|
||||
this.visit_ty(self_type);
|
||||
// Resolve the generic parameters.
|
||||
this.visit_generics(generics);
|
||||
// Resolve the items within the impl.
|
||||
this.with_current_self_type(self_type, |this| {
|
||||
this.with_self_struct_ctor_rib(item_def_id, |this| {
|
||||
debug!("resolve_implementation with_self_struct_ctor_rib");
|
||||
for impl_item in impl_items {
|
||||
this.resolve_visibility(&impl_item.vis);
|
||||
|
||||
// We also need a new scope for the impl item type parameters.
|
||||
let generic_params = HasGenericParams(&impl_item.generics,
|
||||
AssocItemRibKind);
|
||||
this.with_generic_param_rib(generic_params, |this| {
|
||||
use self::ResolutionError::*;
|
||||
match impl_item.node {
|
||||
ImplItemKind::Const(..) => {
|
||||
debug!(
|
||||
"resolve_implementation ImplItemKind::Const",
|
||||
);
|
||||
// If this is a trait impl, ensure the const
|
||||
// exists in trait
|
||||
this.check_trait_item(
|
||||
impl_item.ident,
|
||||
ValueNS,
|
||||
impl_item.span,
|
||||
|n, s| ConstNotMemberOfTrait(n, s),
|
||||
);
|
||||
|
||||
this.with_constant_rib(|this| {
|
||||
visit::walk_impl_item(this, impl_item)
|
||||
});
|
||||
}
|
||||
ImplItemKind::Method(..) => {
|
||||
// If this is a trait impl, ensure the method
|
||||
// exists in trait
|
||||
this.check_trait_item(impl_item.ident,
|
||||
ValueNS,
|
||||
impl_item.span,
|
||||
|n, s| MethodNotMemberOfTrait(n, s));
|
||||
|
||||
visit::walk_impl_item(this, impl_item);
|
||||
}
|
||||
ImplItemKind::TyAlias(ref ty) => {
|
||||
// If this is a trait impl, ensure the type
|
||||
// exists in trait
|
||||
this.check_trait_item(impl_item.ident,
|
||||
TypeNS,
|
||||
impl_item.span,
|
||||
|n, s| TypeNotMemberOfTrait(n, s));
|
||||
|
||||
this.visit_ty(ty);
|
||||
}
|
||||
ImplItemKind::OpaqueTy(ref bounds) => {
|
||||
// If this is a trait impl, ensure the type
|
||||
// exists in trait
|
||||
this.check_trait_item(impl_item.ident,
|
||||
TypeNS,
|
||||
impl_item.span,
|
||||
|n, s| TypeNotMemberOfTrait(n, s));
|
||||
|
||||
for bound in bounds {
|
||||
this.visit_param_bound(bound);
|
||||
}
|
||||
}
|
||||
ImplItemKind::Macro(_) =>
|
||||
panic!("unexpanded macro in resolve!"),
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn check_trait_item<F>(&mut self, ident: Ident, ns: Namespace, span: Span, err: F)
|
||||
where F: FnOnce(Name, &str) -> ResolutionError<'_>
|
||||
{
|
||||
// If there is a TraitRef in scope for an impl, then the method must be in the
|
||||
// trait.
|
||||
if let Some((module, _)) = self.current_trait_ref {
|
||||
if self.resolve_ident_in_module(
|
||||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
ns,
|
||||
None,
|
||||
false,
|
||||
span,
|
||||
).is_err() {
|
||||
let path = &self.current_trait_ref.as_ref().unwrap().1.path;
|
||||
resolve_error(self, span, err(ident.name, &path_names_to_string(path)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_local(&mut self, local: &Local) {
|
||||
// Resolve the type.
|
||||
walk_list!(self, visit_ty, &local.ty);
|
||||
|
||||
// Resolve the initializer.
|
||||
walk_list!(self, visit_expr, &local.init);
|
||||
|
||||
// Resolve the pattern.
|
||||
self.resolve_pattern(&local.pat, PatternSource::Let, &mut FxHashMap::default());
|
||||
}
|
||||
|
||||
// build a map from pattern identifiers to binding-info's.
|
||||
// this is done hygienically. This could arise for a macro
|
||||
// that expands into an or-pattern where one 'x' was from the
|
||||
// user and one 'x' came from the macro.
|
||||
fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap {
|
||||
let mut binding_map = FxHashMap::default();
|
||||
|
||||
pat.walk(&mut |pat| {
|
||||
if let PatKind::Ident(binding_mode, ident, ref sub_pat) = pat.node {
|
||||
if sub_pat.is_some() || match self.partial_res_map.get(&pat.id)
|
||||
.map(|res| res.base_res()) {
|
||||
Some(Res::Local(..)) => true,
|
||||
_ => false,
|
||||
} {
|
||||
let binding_info = BindingInfo { span: ident.span, binding_mode: binding_mode };
|
||||
binding_map.insert(ident, binding_info);
|
||||
}
|
||||
}
|
||||
true
|
||||
});
|
||||
|
||||
binding_map
|
||||
}
|
||||
|
||||
// Checks that all of the arms in an or-pattern have exactly the
|
||||
// same set of bindings, with the same binding modes for each.
|
||||
fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) {
|
||||
if pats.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut missing_vars = FxHashMap::default();
|
||||
let mut inconsistent_vars = FxHashMap::default();
|
||||
for (i, p) in pats.iter().enumerate() {
|
||||
let map_i = self.binding_mode_map(&p);
|
||||
|
||||
for (j, q) in pats.iter().enumerate() {
|
||||
if i == j {
|
||||
continue;
|
||||
}
|
||||
|
||||
let map_j = self.binding_mode_map(&q);
|
||||
for (&key, &binding_i) in &map_i {
|
||||
if map_j.is_empty() { // Account for missing bindings when
|
||||
let binding_error = missing_vars // `map_j` has none.
|
||||
.entry(key.name)
|
||||
.or_insert(BindingError {
|
||||
name: key.name,
|
||||
origin: BTreeSet::new(),
|
||||
target: BTreeSet::new(),
|
||||
});
|
||||
binding_error.origin.insert(binding_i.span);
|
||||
binding_error.target.insert(q.span);
|
||||
}
|
||||
for (&key_j, &binding_j) in &map_j {
|
||||
match map_i.get(&key_j) {
|
||||
None => { // missing binding
|
||||
let binding_error = missing_vars
|
||||
.entry(key_j.name)
|
||||
.or_insert(BindingError {
|
||||
name: key_j.name,
|
||||
origin: BTreeSet::new(),
|
||||
target: BTreeSet::new(),
|
||||
});
|
||||
binding_error.origin.insert(binding_j.span);
|
||||
binding_error.target.insert(p.span);
|
||||
}
|
||||
Some(binding_i) => { // check consistent binding
|
||||
if binding_i.binding_mode != binding_j.binding_mode {
|
||||
inconsistent_vars
|
||||
.entry(key.name)
|
||||
.or_insert((binding_j.span, binding_i.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut missing_vars = missing_vars.iter().collect::<Vec<_>>();
|
||||
missing_vars.sort();
|
||||
for (_, v) in missing_vars {
|
||||
resolve_error(self,
|
||||
*v.origin.iter().next().unwrap(),
|
||||
ResolutionError::VariableNotBoundInPattern(v));
|
||||
}
|
||||
let mut inconsistent_vars = inconsistent_vars.iter().collect::<Vec<_>>();
|
||||
inconsistent_vars.sort();
|
||||
for (name, v) in inconsistent_vars {
|
||||
resolve_error(self, v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1));
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_arm(&mut self, arm: &Arm) {
|
||||
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
|
||||
|
||||
self.resolve_pats(&arm.pats, PatternSource::Match);
|
||||
|
||||
if let Some(ref expr) = arm.guard {
|
||||
self.visit_expr(expr)
|
||||
}
|
||||
self.visit_expr(&arm.body);
|
||||
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
|
||||
/// Arising from `source`, resolve a sequence of patterns (top level or-patterns).
|
||||
fn resolve_pats(&mut self, pats: &[P<Pat>], source: PatternSource) {
|
||||
let mut bindings_list = FxHashMap::default();
|
||||
for pat in pats {
|
||||
self.resolve_pattern(pat, source, &mut bindings_list);
|
||||
}
|
||||
// This has to happen *after* we determine which pat_idents are variants
|
||||
self.check_consistent_bindings(pats);
|
||||
}
|
||||
|
||||
fn resolve_block(&mut self, block: &Block) {
|
||||
debug!("(resolving block) entering block");
|
||||
// Move down in the graph, if there's an anonymous module rooted here.
|
||||
let orig_module = self.current_module;
|
||||
let anonymous_module = self.block_map.get(&block.id).cloned(); // clones a reference
|
||||
|
||||
let mut num_macro_definition_ribs = 0;
|
||||
if let Some(anonymous_module) = anonymous_module {
|
||||
debug!("(resolving block) found anonymous module, moving down");
|
||||
self.ribs[ValueNS].push(Rib::new(ModuleRibKind(anonymous_module)));
|
||||
self.ribs[TypeNS].push(Rib::new(ModuleRibKind(anonymous_module)));
|
||||
self.current_module = anonymous_module;
|
||||
self.finalize_current_module_macro_resolutions();
|
||||
} else {
|
||||
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
|
||||
}
|
||||
|
||||
// Descend into the block.
|
||||
for stmt in &block.stmts {
|
||||
if let ast::StmtKind::Item(ref item) = stmt.node {
|
||||
if let ast::ItemKind::MacroDef(..) = item.node {
|
||||
num_macro_definition_ribs += 1;
|
||||
let res = self.definitions.local_def_id(item.id);
|
||||
self.ribs[ValueNS].push(Rib::new(MacroDefinition(res)));
|
||||
self.label_ribs.push(Rib::new(MacroDefinition(res)));
|
||||
}
|
||||
}
|
||||
|
||||
self.visit_stmt(stmt);
|
||||
}
|
||||
|
||||
// Move back up.
|
||||
self.current_module = orig_module;
|
||||
for _ in 0 .. num_macro_definition_ribs {
|
||||
self.ribs[ValueNS].pop();
|
||||
self.label_ribs.pop();
|
||||
}
|
||||
self.ribs[ValueNS].pop();
|
||||
if anonymous_module.is_some() {
|
||||
self.ribs[TypeNS].pop();
|
||||
}
|
||||
debug!("(resolving block) leaving block");
|
||||
}
|
||||
|
||||
fn fresh_binding(&mut self,
|
||||
ident: Ident,
|
||||
pat_id: NodeId,
|
||||
outer_pat_id: NodeId,
|
||||
pat_src: PatternSource,
|
||||
bindings: &mut FxHashMap<Ident, NodeId>)
|
||||
-> Res {
|
||||
// Add the binding to the local ribs, if it
|
||||
// doesn't already exist in the bindings map. (We
|
||||
// must not add it if it's in the bindings map
|
||||
// because that breaks the assumptions later
|
||||
// passes make about or-patterns.)
|
||||
let ident = ident.modern_and_legacy();
|
||||
let mut res = Res::Local(pat_id);
|
||||
match bindings.get(&ident).cloned() {
|
||||
Some(id) if id == outer_pat_id => {
|
||||
// `Variant(a, a)`, error
|
||||
resolve_error(
|
||||
self,
|
||||
ident.span,
|
||||
ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(
|
||||
&ident.as_str())
|
||||
);
|
||||
}
|
||||
Some(..) if pat_src == PatternSource::FnParam => {
|
||||
// `fn f(a: u8, a: u8)`, error
|
||||
resolve_error(
|
||||
self,
|
||||
ident.span,
|
||||
ResolutionError::IdentifierBoundMoreThanOnceInParameterList(
|
||||
&ident.as_str())
|
||||
);
|
||||
}
|
||||
Some(..) if pat_src == PatternSource::Match ||
|
||||
pat_src == PatternSource::Let => {
|
||||
// `Variant1(a) | Variant2(a)`, ok
|
||||
// Reuse definition from the first `a`.
|
||||
res = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident];
|
||||
}
|
||||
Some(..) => {
|
||||
span_bug!(ident.span, "two bindings with the same name from \
|
||||
unexpected pattern source {:?}", pat_src);
|
||||
}
|
||||
None => {
|
||||
// A completely fresh binding, add to the lists if it's valid.
|
||||
if ident.name != kw::Invalid {
|
||||
bindings.insert(ident, outer_pat_id);
|
||||
self.ribs[ValueNS].last_mut().unwrap().bindings.insert(ident, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn resolve_pattern(&mut self,
|
||||
pat: &Pat,
|
||||
pat_src: PatternSource,
|
||||
// Maps idents to the node ID for the
|
||||
// outermost pattern that binds them.
|
||||
bindings: &mut FxHashMap<Ident, NodeId>) {
|
||||
// Visit all direct subpatterns of this pattern.
|
||||
let outer_pat_id = pat.id;
|
||||
pat.walk(&mut |pat| {
|
||||
debug!("resolve_pattern pat={:?} node={:?}", pat, pat.node);
|
||||
match pat.node {
|
||||
PatKind::Ident(bmode, ident, ref opt_pat) => {
|
||||
// First try to resolve the identifier as some existing
|
||||
// entity, then fall back to a fresh binding.
|
||||
let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS,
|
||||
None, pat.span)
|
||||
.and_then(LexicalScopeBinding::item);
|
||||
let res = binding.map(NameBinding::res).and_then(|res| {
|
||||
let is_syntactic_ambiguity = opt_pat.is_none() &&
|
||||
bmode == BindingMode::ByValue(Mutability::Immutable);
|
||||
match res {
|
||||
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) |
|
||||
Res::Def(DefKind::Const, _) if is_syntactic_ambiguity => {
|
||||
// Disambiguate in favor of a unit struct/variant
|
||||
// or constant pattern.
|
||||
self.record_use(ident, ValueNS, binding.unwrap(), false);
|
||||
Some(res)
|
||||
}
|
||||
Res::Def(DefKind::Ctor(..), _)
|
||||
| Res::Def(DefKind::Const, _)
|
||||
| Res::Def(DefKind::Static, _) => {
|
||||
// This is unambiguously a fresh binding, either syntactically
|
||||
// (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves
|
||||
// to something unusable as a pattern (e.g., constructor function),
|
||||
// but we still conservatively report an error, see
|
||||
// issues/33118#issuecomment-233962221 for one reason why.
|
||||
resolve_error(
|
||||
self,
|
||||
ident.span,
|
||||
ResolutionError::BindingShadowsSomethingUnacceptable(
|
||||
pat_src.descr(), ident.name, binding.unwrap())
|
||||
);
|
||||
None
|
||||
}
|
||||
Res::Def(DefKind::Fn, _) | Res::Err => {
|
||||
// These entities are explicitly allowed
|
||||
// to be shadowed by fresh bindings.
|
||||
None
|
||||
}
|
||||
res => {
|
||||
span_bug!(ident.span, "unexpected resolution for an \
|
||||
identifier in pattern: {:?}", res);
|
||||
}
|
||||
}
|
||||
}).unwrap_or_else(|| {
|
||||
self.fresh_binding(ident, pat.id, outer_pat_id, pat_src, bindings)
|
||||
});
|
||||
|
||||
self.record_partial_res(pat.id, PartialRes::new(res));
|
||||
}
|
||||
|
||||
PatKind::TupleStruct(ref path, ..) => {
|
||||
self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct);
|
||||
}
|
||||
|
||||
PatKind::Path(ref qself, ref path) => {
|
||||
self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat);
|
||||
}
|
||||
|
||||
PatKind::Struct(ref path, ..) => {
|
||||
self.smart_resolve_path(pat.id, None, path, PathSource::Struct);
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
true
|
||||
});
|
||||
|
||||
visit::walk_pat(self, pat);
|
||||
}
|
||||
|
||||
// High-level and context dependent path resolution routine.
|
||||
// Resolves the path and records the resolution into definition map.
|
||||
// If resolution fails tries several techniques to find likely
|
||||
// resolution candidates, suggest imports or other help, and report
|
||||
// errors in user friendly way.
|
||||
fn smart_resolve_path(&mut self,
|
||||
id: NodeId,
|
||||
qself: Option<&QSelf>,
|
||||
path: &Path,
|
||||
source: PathSource<'_>) {
|
||||
self.smart_resolve_path_fragment(
|
||||
id,
|
||||
qself,
|
||||
&Segment::from_path(path),
|
||||
path.span,
|
||||
source,
|
||||
CrateLint::SimplePath(id),
|
||||
);
|
||||
}
|
||||
|
||||
fn smart_resolve_path_fragment(&mut self,
|
||||
id: NodeId,
|
||||
qself: Option<&QSelf>,
|
||||
path: &[Segment],
|
||||
span: Span,
|
||||
source: PathSource<'_>,
|
||||
crate_lint: CrateLint)
|
||||
-> PartialRes {
|
||||
let ns = source.namespace();
|
||||
let is_expected = &|res| source.is_expected(res);
|
||||
|
||||
let report_errors = |this: &mut Self, res: Option<Res>| {
|
||||
let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res);
|
||||
let def_id = this.current_module.normal_ancestor_id;
|
||||
let node_id = this.definitions.as_local_node_id(def_id).unwrap();
|
||||
let better = res.is_some();
|
||||
this.use_injections.push(UseError { err, candidates, node_id, better });
|
||||
PartialRes::new(Res::Err)
|
||||
};
|
||||
|
||||
let partial_res = match self.resolve_qpath_anywhere(
|
||||
id,
|
||||
qself,
|
||||
path,
|
||||
ns,
|
||||
span,
|
||||
source.defer_to_typeck(),
|
||||
source.global_by_default(),
|
||||
crate_lint,
|
||||
) {
|
||||
Some(partial_res) if partial_res.unresolved_segments() == 0 => {
|
||||
if is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err {
|
||||
partial_res
|
||||
} else {
|
||||
// Add a temporary hack to smooth the transition to new struct ctor
|
||||
// visibility rules. See #38932 for more details.
|
||||
let mut res = None;
|
||||
if let Res::Def(DefKind::Struct, def_id) = partial_res.base_res() {
|
||||
if let Some((ctor_res, ctor_vis))
|
||||
= self.struct_constructors.get(&def_id).cloned() {
|
||||
if is_expected(ctor_res) && self.is_accessible(ctor_vis) {
|
||||
let lint = lint::builtin::LEGACY_CONSTRUCTOR_VISIBILITY;
|
||||
self.session.buffer_lint(lint, id, span,
|
||||
"private struct constructors are not usable through \
|
||||
re-exports in outer modules",
|
||||
);
|
||||
res = Some(PartialRes::new(ctor_res));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res.unwrap_or_else(|| report_errors(self, Some(partial_res.base_res())))
|
||||
}
|
||||
}
|
||||
Some(partial_res) if source.defer_to_typeck() => {
|
||||
// Not fully resolved associated item `T::A::B` or `<T as Tr>::A::B`
|
||||
// or `<T>::A::B`. If `B` should be resolved in value namespace then
|
||||
// it needs to be added to the trait map.
|
||||
if ns == ValueNS {
|
||||
let item_name = path.last().unwrap().ident;
|
||||
let traits = self.get_traits_containing_item(item_name, ns);
|
||||
self.trait_map.insert(id, traits);
|
||||
}
|
||||
|
||||
let mut std_path = vec![Segment::from_ident(Ident::with_empty_ctxt(sym::std))];
|
||||
std_path.extend(path);
|
||||
if self.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) {
|
||||
let cl = CrateLint::No;
|
||||
let ns = Some(ns);
|
||||
if let PathResult::Module(_) | PathResult::NonModule(_) =
|
||||
self.resolve_path_without_parent_scope(&std_path, ns, false, span, cl)
|
||||
{
|
||||
// check if we wrote `str::from_utf8` instead of `std::str::from_utf8`
|
||||
let item_span = path.iter().last().map(|segment| segment.ident.span)
|
||||
.unwrap_or(span);
|
||||
debug!("accessed item from `std` submodule as a bare type {:?}", std_path);
|
||||
let mut hm = self.session.confused_type_with_std_module.borrow_mut();
|
||||
hm.insert(item_span, span);
|
||||
// In some places (E0223) we only have access to the full path
|
||||
hm.insert(span, span);
|
||||
}
|
||||
}
|
||||
partial_res
|
||||
}
|
||||
_ => report_errors(self, None)
|
||||
};
|
||||
|
||||
if let PathSource::TraitItem(..) = source {} else {
|
||||
// Avoid recording definition of `A::B` in `<T as A>::B::C`.
|
||||
self.record_partial_res(id, partial_res);
|
||||
}
|
||||
partial_res
|
||||
}
|
||||
|
||||
/// Only used in a specific case of type ascription suggestions
|
||||
#[doc(hidden)]
|
||||
fn get_colon_suggestion_span(&self, start: Span) -> Span {
|
||||
let cm = self.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.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 self_type_is_available(&mut self, span: Span) -> bool {
|
||||
let binding = self.resolve_ident_in_lexical_scope(
|
||||
Ident::with_empty_ctxt(kw::SelfUpper),
|
||||
TypeNS,
|
||||
None,
|
||||
span,
|
||||
);
|
||||
if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
|
||||
}
|
||||
|
||||
fn self_value_is_available(&mut self, self_span: Span, path_span: Span) -> bool {
|
||||
let ident = Ident::new(kw::SelfLower, self_span);
|
||||
let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, path_span);
|
||||
if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
|
||||
}
|
||||
|
||||
// Resolve in alternative namespaces if resolution in the primary namespace fails.
|
||||
fn resolve_qpath_anywhere(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
qself: Option<&QSelf>,
|
||||
path: &[Segment],
|
||||
primary_ns: Namespace,
|
||||
span: Span,
|
||||
defer_to_typeck: bool,
|
||||
global_by_default: bool,
|
||||
crate_lint: CrateLint,
|
||||
) -> Option<PartialRes> {
|
||||
let mut fin_res = None;
|
||||
for (i, ns) in [primary_ns, TypeNS, ValueNS].iter().cloned().enumerate() {
|
||||
if i == 0 || ns != primary_ns {
|
||||
match self.resolve_qpath(id, qself, path, ns, span, global_by_default, crate_lint) {
|
||||
// If defer_to_typeck, then resolution > no resolution,
|
||||
// otherwise full resolution > partial resolution > no resolution.
|
||||
Some(partial_res) if partial_res.unresolved_segments() == 0 ||
|
||||
defer_to_typeck =>
|
||||
return Some(partial_res),
|
||||
partial_res => if fin_res.is_none() { fin_res = partial_res },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// `MacroNS`
|
||||
assert!(primary_ns != MacroNS);
|
||||
if qself.is_none() {
|
||||
let path_seg = |seg: &Segment| ast::PathSegment::from_ident(seg.ident);
|
||||
let path = Path { segments: path.iter().map(path_seg).collect(), span };
|
||||
let parent_scope =
|
||||
ParentScope { module: self.current_module, ..self.dummy_parent_scope() };
|
||||
if let Ok((_, res)) =
|
||||
self.resolve_macro_path(&path, None, &parent_scope, false, false) {
|
||||
return Some(PartialRes::new(res));
|
||||
}
|
||||
}
|
||||
|
||||
fin_res
|
||||
}
|
||||
|
||||
/// Handles paths that may refer to associated items.
|
||||
fn resolve_qpath(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
qself: Option<&QSelf>,
|
||||
path: &[Segment],
|
||||
ns: Namespace,
|
||||
span: Span,
|
||||
global_by_default: bool,
|
||||
crate_lint: CrateLint,
|
||||
) -> Option<PartialRes> {
|
||||
debug!(
|
||||
"resolve_qpath(id={:?}, qself={:?}, path={:?}, \
|
||||
ns={:?}, span={:?}, global_by_default={:?})",
|
||||
id,
|
||||
qself,
|
||||
path,
|
||||
ns,
|
||||
span,
|
||||
global_by_default,
|
||||
);
|
||||
|
||||
if let Some(qself) = qself {
|
||||
if qself.position == 0 {
|
||||
// This is a case like `<T>::B`, where there is no
|
||||
// trait to resolve. In that case, we leave the `B`
|
||||
// segment to be resolved by type-check.
|
||||
return Some(PartialRes::with_unresolved_segments(
|
||||
Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)), path.len()
|
||||
));
|
||||
}
|
||||
|
||||
// Make sure `A::B` in `<T as A::B>::C` is a trait item.
|
||||
//
|
||||
// Currently, `path` names the full item (`A::B::C`, in
|
||||
// our example). so we extract the prefix of that that is
|
||||
// the trait (the slice upto and including
|
||||
// `qself.position`). And then we recursively resolve that,
|
||||
// but with `qself` set to `None`.
|
||||
//
|
||||
// However, setting `qself` to none (but not changing the
|
||||
// span) loses the information about where this path
|
||||
// *actually* appears, so for the purposes of the crate
|
||||
// lint we pass along information that this is the trait
|
||||
// name from a fully qualified path, and this also
|
||||
// contains the full span (the `CrateLint::QPathTrait`).
|
||||
let ns = if qself.position + 1 == path.len() { ns } else { TypeNS };
|
||||
let partial_res = self.smart_resolve_path_fragment(
|
||||
id,
|
||||
None,
|
||||
&path[..=qself.position],
|
||||
span,
|
||||
PathSource::TraitItem(ns),
|
||||
CrateLint::QPathTrait {
|
||||
qpath_id: id,
|
||||
qpath_span: qself.path_span,
|
||||
},
|
||||
);
|
||||
|
||||
// The remaining segments (the `C` in our example) will
|
||||
// have to be resolved by type-check, since that requires doing
|
||||
// trait resolution.
|
||||
return Some(PartialRes::with_unresolved_segments(
|
||||
partial_res.base_res(),
|
||||
partial_res.unresolved_segments() + path.len() - qself.position - 1,
|
||||
));
|
||||
}
|
||||
|
||||
let result = match self.resolve_path_without_parent_scope(
|
||||
&path,
|
||||
Some(ns),
|
||||
true,
|
||||
span,
|
||||
crate_lint,
|
||||
) {
|
||||
PathResult::NonModule(path_res) => path_res,
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => {
|
||||
PartialRes::new(module.res().unwrap())
|
||||
}
|
||||
// In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we
|
||||
// don't report an error right away, but try to fallback to a primitive type.
|
||||
// So, we are still able to successfully resolve something like
|
||||
//
|
||||
// use std::u8; // bring module u8 in scope
|
||||
// fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8
|
||||
// u8::max_value() // OK, resolves to associated function <u8>::max_value,
|
||||
// // not to non-existent std::u8::max_value
|
||||
// }
|
||||
//
|
||||
// Such behavior is required for backward compatibility.
|
||||
// The same fallback is used when `a` resolves to nothing.
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(_)) |
|
||||
PathResult::Failed { .. }
|
||||
if (ns == TypeNS || path.len() > 1) &&
|
||||
self.primitive_type_table.primitive_types
|
||||
.contains_key(&path[0].ident.name) => {
|
||||
let prim = self.primitive_type_table.primitive_types[&path[0].ident.name];
|
||||
PartialRes::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1)
|
||||
}
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
|
||||
PartialRes::new(module.res().unwrap()),
|
||||
PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
|
||||
resolve_error(self, span, ResolutionError::FailedToResolve { label, suggestion });
|
||||
PartialRes::new(Res::Err)
|
||||
}
|
||||
PathResult::Module(..) | PathResult::Failed { .. } => return None,
|
||||
PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"),
|
||||
};
|
||||
|
||||
if path.len() > 1 && !global_by_default && result.base_res() != Res::Err &&
|
||||
path[0].ident.name != kw::PathRoot &&
|
||||
path[0].ident.name != kw::DollarCrate {
|
||||
let unqualified_result = {
|
||||
match self.resolve_path_without_parent_scope(
|
||||
&[*path.last().unwrap()],
|
||||
Some(ns),
|
||||
false,
|
||||
span,
|
||||
CrateLint::No,
|
||||
) {
|
||||
PathResult::NonModule(path_res) => path_res.base_res(),
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
|
||||
module.res().unwrap(),
|
||||
_ => return Some(result),
|
||||
}
|
||||
};
|
||||
if result.base_res() == unqualified_result {
|
||||
let lint = lint::builtin::UNUSED_QUALIFICATIONS;
|
||||
self.session.buffer_lint(lint, id, span, "unnecessary qualification")
|
||||
}
|
||||
}
|
||||
|
||||
Some(result)
|
||||
}
|
||||
|
||||
fn resolve_path_without_parent_scope(
|
||||
&mut self,
|
||||
path: &[Segment],
|
||||
opt_ns: Option<Namespace>, // `None` indicates a module path in import
|
||||
record_used: bool,
|
||||
path_span: Span,
|
||||
crate_lint: CrateLint,
|
||||
) -> PathResult<'a> {
|
||||
// Macro and import paths must have full parent scope available during resolution,
|
||||
// other paths will do okay with parent module alone.
|
||||
assert!(opt_ns != None && opt_ns != Some(MacroNS));
|
||||
let parent_scope = ParentScope { module: self.current_module, ..self.dummy_parent_scope() };
|
||||
self.resolve_path(path, opt_ns, &parent_scope, record_used, path_span, crate_lint)
|
||||
}
|
||||
|
||||
fn resolve_path(
|
||||
&mut self,
|
||||
path: &[Segment],
|
||||
@@ -3869,11 +1730,25 @@ fn resolve_path(
|
||||
record_used: bool,
|
||||
path_span: Span,
|
||||
crate_lint: CrateLint,
|
||||
) -> PathResult<'a> {
|
||||
self.resolve_path_with_ribs(
|
||||
path, opt_ns, parent_scope, record_used, path_span, crate_lint, None
|
||||
)
|
||||
}
|
||||
|
||||
fn resolve_path_with_ribs(
|
||||
&mut self,
|
||||
path: &[Segment],
|
||||
opt_ns: Option<Namespace>, // `None` indicates a module path in import
|
||||
parent_scope: &ParentScope<'a>,
|
||||
record_used: bool,
|
||||
path_span: Span,
|
||||
crate_lint: CrateLint,
|
||||
ribs: Option<&PerNS<Vec<Rib<'a>>>>,
|
||||
) -> PathResult<'a> {
|
||||
let mut module = None;
|
||||
let mut allow_super = true;
|
||||
let mut second_binding = None;
|
||||
self.current_module = parent_scope.module;
|
||||
|
||||
debug!(
|
||||
"resolve_path(path={:?}, opt_ns={:?}, record_used={:?}, \
|
||||
@@ -3910,7 +1785,7 @@ fn resolve_path(
|
||||
if allow_super && name == kw::Super {
|
||||
let mut ctxt = ident.span.ctxt().modern();
|
||||
let self_module = match i {
|
||||
0 => Some(self.resolve_self(&mut ctxt, self.current_module)),
|
||||
0 => Some(self.resolve_self(&mut ctxt, parent_scope.module)),
|
||||
_ => match module {
|
||||
Some(ModuleOrUniformRoot::Module(module)) => Some(module),
|
||||
_ => None,
|
||||
@@ -3935,7 +1810,7 @@ fn resolve_path(
|
||||
if name == kw::SelfLower {
|
||||
let mut ctxt = ident.span.ctxt().modern();
|
||||
module = Some(ModuleOrUniformRoot::Module(
|
||||
self.resolve_self(&mut ctxt, self.current_module)));
|
||||
self.resolve_self(&mut ctxt, parent_scope.module)));
|
||||
continue;
|
||||
}
|
||||
if name == kw::PathRoot && ident.span.rust_2018() {
|
||||
@@ -3980,16 +1855,19 @@ fn resolve_path(
|
||||
}
|
||||
|
||||
let binding = if let Some(module) = module {
|
||||
self.resolve_ident_in_module(module, ident, ns, None, record_used, path_span)
|
||||
} else if opt_ns.is_none() || opt_ns == Some(MacroNS) {
|
||||
assert!(ns == TypeNS);
|
||||
let scopes = if opt_ns.is_none() { ScopeSet::Import(ns) } else { ScopeSet::Module };
|
||||
self.resolve_ident_in_module(
|
||||
module, ident, ns, parent_scope, record_used, path_span
|
||||
)
|
||||
} else if ribs.is_none() || opt_ns.is_none() || opt_ns == Some(MacroNS) {
|
||||
let scopes = ScopeSet::All(ns, opt_ns.is_none());
|
||||
self.early_resolve_ident_in_lexical_scope(ident, scopes, parent_scope, record_used,
|
||||
record_used, path_span)
|
||||
} else {
|
||||
let record_used_id =
|
||||
if record_used { crate_lint.node_id().or(Some(CRATE_NODE_ID)) } else { None };
|
||||
match self.resolve_ident_in_lexical_scope(ident, ns, record_used_id, path_span) {
|
||||
match self.resolve_ident_in_lexical_scope(
|
||||
ident, ns, parent_scope, record_used_id, path_span, &ribs.unwrap()[ns]
|
||||
) {
|
||||
// we found a locally-imported or available item/module
|
||||
Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
|
||||
// we found a local variable or type param
|
||||
@@ -4176,28 +2054,28 @@ fn lint_if_path_starts_with_module(
|
||||
// Validate a local resolution (from ribs).
|
||||
fn validate_res_from_ribs(
|
||||
&mut self,
|
||||
ns: Namespace,
|
||||
rib_index: usize,
|
||||
res: Res,
|
||||
record_used: bool,
|
||||
span: Span,
|
||||
all_ribs: &[Rib<'a>],
|
||||
) -> Res {
|
||||
debug!("validate_res_from_ribs({:?})", res);
|
||||
let ribs = &self.ribs[ns][rib_index + 1..];
|
||||
let ribs = &all_ribs[rib_index + 1..];
|
||||
|
||||
// An invalid forward use of a type parameter from a previous default.
|
||||
if let ForwardTyParamBanRibKind = self.ribs[ns][rib_index].kind {
|
||||
if let ForwardTyParamBanRibKind = all_ribs[rib_index].kind {
|
||||
if record_used {
|
||||
resolve_error(self, span, ResolutionError::ForwardDeclaredTyParam);
|
||||
self.report_error(span, ResolutionError::ForwardDeclaredTyParam);
|
||||
}
|
||||
assert_eq!(res, Res::Err);
|
||||
return Res::Err;
|
||||
}
|
||||
|
||||
// An invalid use of a type parameter as the type of a const parameter.
|
||||
if let TyParamAsConstParamTy = self.ribs[ns][rib_index].kind {
|
||||
if let TyParamAsConstParamTy = all_ribs[rib_index].kind {
|
||||
if record_used {
|
||||
resolve_error(self, span, ResolutionError::ConstParamDependentOnTypeParam);
|
||||
self.report_error(span, ResolutionError::ConstParamDependentOnTypeParam);
|
||||
}
|
||||
assert_eq!(res, Res::Err);
|
||||
return Res::Err;
|
||||
@@ -4229,14 +2107,14 @@ fn validate_res_from_ribs(
|
||||
ConstantItemRibKind => {
|
||||
// Still doesn't deal with upvars
|
||||
if record_used {
|
||||
resolve_error(self, span, AttemptToUseNonConstantValueInConstant);
|
||||
self.report_error(span, AttemptToUseNonConstantValueInConstant);
|
||||
}
|
||||
return Res::Err;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(res_err) = res_err {
|
||||
resolve_error(self, span, res_err);
|
||||
self.report_error(span, res_err);
|
||||
return Res::Err;
|
||||
}
|
||||
}
|
||||
@@ -4251,10 +2129,8 @@ fn validate_res_from_ribs(
|
||||
ItemRibKind | FnItemRibKind => {
|
||||
// This was an attempt to use a type parameter outside its scope.
|
||||
if record_used {
|
||||
resolve_error(
|
||||
self,
|
||||
span,
|
||||
ResolutionError::GenericParamsFromOuterFunction(res),
|
||||
self.report_error(
|
||||
span, ResolutionError::GenericParamsFromOuterFunction(res)
|
||||
);
|
||||
}
|
||||
return Res::Err;
|
||||
@@ -4274,10 +2150,8 @@ fn validate_res_from_ribs(
|
||||
if let ItemRibKind | FnItemRibKind = rib.kind {
|
||||
// This was an attempt to use a const parameter outside its scope.
|
||||
if record_used {
|
||||
resolve_error(
|
||||
self,
|
||||
span,
|
||||
ResolutionError::GenericParamsFromOuterFunction(res),
|
||||
self.report_error(
|
||||
span, ResolutionError::GenericParamsFromOuterFunction(res)
|
||||
);
|
||||
}
|
||||
return Res::Err;
|
||||
@@ -4289,299 +2163,6 @@ fn validate_res_from_ribs(
|
||||
res
|
||||
}
|
||||
|
||||
fn with_resolved_label<F>(&mut self, label: Option<Label>, id: NodeId, f: F)
|
||||
where F: FnOnce(&mut Resolver<'_>)
|
||||
{
|
||||
if let Some(label) = label {
|
||||
self.unused_labels.insert(id, label.ident.span);
|
||||
self.with_label_rib(|this| {
|
||||
let ident = label.ident.modern_and_legacy();
|
||||
this.label_ribs.last_mut().unwrap().bindings.insert(ident, id);
|
||||
f(this);
|
||||
});
|
||||
} else {
|
||||
f(self);
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_labeled_block(&mut self, label: Option<Label>, id: NodeId, block: &Block) {
|
||||
self.with_resolved_label(label, id, |this| this.visit_block(block));
|
||||
}
|
||||
|
||||
fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
|
||||
// First, record candidate traits for this expression if it could
|
||||
// result in the invocation of a method call.
|
||||
|
||||
self.record_candidate_traits_for_expr_if_necessary(expr);
|
||||
|
||||
// Next, resolve the node.
|
||||
match expr.node {
|
||||
ExprKind::Path(ref qself, ref path) => {
|
||||
self.smart_resolve_path(expr.id, qself.as_ref(), path, PathSource::Expr(parent));
|
||||
visit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
ExprKind::Struct(ref path, ..) => {
|
||||
self.smart_resolve_path(expr.id, None, path, PathSource::Struct);
|
||||
visit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
|
||||
let node_id = self.search_label(label.ident, |rib, ident| {
|
||||
rib.bindings.get(&ident.modern_and_legacy()).cloned()
|
||||
});
|
||||
match node_id {
|
||||
None => {
|
||||
// Search again for close matches...
|
||||
// Picks the first label that is "close enough", which is not necessarily
|
||||
// the closest match
|
||||
let close_match = self.search_label(label.ident, |rib, ident| {
|
||||
let names = rib.bindings.iter().filter_map(|(id, _)| {
|
||||
if id.span.ctxt() == label.ident.span.ctxt() {
|
||||
Some(&id.name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
find_best_match_for_name(names, &*ident.as_str(), None)
|
||||
});
|
||||
self.record_partial_res(expr.id, PartialRes::new(Res::Err));
|
||||
resolve_error(self,
|
||||
label.ident.span,
|
||||
ResolutionError::UndeclaredLabel(&label.ident.as_str(),
|
||||
close_match));
|
||||
}
|
||||
Some(node_id) => {
|
||||
// Since this res is a label, it is never read.
|
||||
self.label_res_map.insert(expr.id, node_id);
|
||||
self.unused_labels.remove(&node_id);
|
||||
}
|
||||
}
|
||||
|
||||
// visit `break` argument if any
|
||||
visit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
ExprKind::Let(ref pats, ref scrutinee) => {
|
||||
self.visit_expr(scrutinee);
|
||||
self.resolve_pats(pats, PatternSource::Let);
|
||||
}
|
||||
|
||||
ExprKind::If(ref cond, ref then, ref opt_else) => {
|
||||
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
|
||||
self.visit_expr(cond);
|
||||
self.visit_block(then);
|
||||
self.ribs[ValueNS].pop();
|
||||
|
||||
opt_else.as_ref().map(|expr| self.visit_expr(expr));
|
||||
}
|
||||
|
||||
ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block),
|
||||
|
||||
ExprKind::While(ref subexpression, ref block, label) => {
|
||||
self.with_resolved_label(label, expr.id, |this| {
|
||||
this.ribs[ValueNS].push(Rib::new(NormalRibKind));
|
||||
this.visit_expr(subexpression);
|
||||
this.visit_block(block);
|
||||
this.ribs[ValueNS].pop();
|
||||
});
|
||||
}
|
||||
|
||||
ExprKind::ForLoop(ref pattern, ref subexpression, ref block, label) => {
|
||||
self.visit_expr(subexpression);
|
||||
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
|
||||
self.resolve_pattern(pattern, PatternSource::For, &mut FxHashMap::default());
|
||||
|
||||
self.resolve_labeled_block(label, expr.id, block);
|
||||
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
|
||||
ExprKind::Block(ref block, label) => self.resolve_labeled_block(label, block.id, block),
|
||||
|
||||
// Equivalent to `visit::walk_expr` + passing some context to children.
|
||||
ExprKind::Field(ref subexpression, _) => {
|
||||
self.resolve_expr(subexpression, Some(expr));
|
||||
}
|
||||
ExprKind::MethodCall(ref segment, ref arguments) => {
|
||||
let mut arguments = arguments.iter();
|
||||
self.resolve_expr(arguments.next().unwrap(), Some(expr));
|
||||
for argument in arguments {
|
||||
self.resolve_expr(argument, None);
|
||||
}
|
||||
self.visit_path_segment(expr.span, segment);
|
||||
}
|
||||
|
||||
ExprKind::Call(ref callee, ref arguments) => {
|
||||
self.resolve_expr(callee, Some(expr));
|
||||
for argument in arguments {
|
||||
self.resolve_expr(argument, None);
|
||||
}
|
||||
}
|
||||
ExprKind::Type(ref type_expr, _) => {
|
||||
self.current_type_ascription.push(type_expr.span);
|
||||
visit::walk_expr(self, expr);
|
||||
self.current_type_ascription.pop();
|
||||
}
|
||||
// `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to
|
||||
// resolve the arguments within the proper scopes so that usages of them inside the
|
||||
// closure are detected as upvars rather than normal closure arg usages.
|
||||
ExprKind::Closure(
|
||||
_, IsAsync::Async { .. }, _,
|
||||
ref fn_decl, ref body, _span,
|
||||
) => {
|
||||
let rib_kind = NormalRibKind;
|
||||
self.ribs[ValueNS].push(Rib::new(rib_kind));
|
||||
// Resolve arguments:
|
||||
let mut bindings_list = FxHashMap::default();
|
||||
for argument in &fn_decl.inputs {
|
||||
self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
|
||||
self.visit_ty(&argument.ty);
|
||||
}
|
||||
// No need to resolve return type-- the outer closure return type is
|
||||
// FunctionRetTy::Default
|
||||
|
||||
// Now resolve the inner closure
|
||||
{
|
||||
// No need to resolve arguments: the inner closure has none.
|
||||
// Resolve the return type:
|
||||
visit::walk_fn_ret_ty(self, &fn_decl.output);
|
||||
// Resolve the body
|
||||
self.visit_expr(body);
|
||||
}
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
_ => {
|
||||
visit::walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &Expr) {
|
||||
match expr.node {
|
||||
ExprKind::Field(_, ident) => {
|
||||
// FIXME(#6890): Even though you can't treat a method like a
|
||||
// field, we need to add any trait methods we find that match
|
||||
// the field name so that we can do some nice error reporting
|
||||
// later on in typeck.
|
||||
let traits = self.get_traits_containing_item(ident, ValueNS);
|
||||
self.trait_map.insert(expr.id, traits);
|
||||
}
|
||||
ExprKind::MethodCall(ref segment, ..) => {
|
||||
debug!("(recording candidate traits for expr) recording traits for {}",
|
||||
expr.id);
|
||||
let traits = self.get_traits_containing_item(segment.ident, ValueNS);
|
||||
self.trait_map.insert(expr.id, traits);
|
||||
}
|
||||
_ => {
|
||||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_traits_containing_item(&mut self, mut ident: Ident, ns: Namespace)
|
||||
-> Vec<TraitCandidate> {
|
||||
debug!("(getting traits containing item) looking for '{}'", ident.name);
|
||||
|
||||
let mut found_traits = Vec::new();
|
||||
// Look for the current trait.
|
||||
if let Some((module, _)) = self.current_trait_ref {
|
||||
if self.resolve_ident_in_module(
|
||||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
ns,
|
||||
None,
|
||||
false,
|
||||
module.span,
|
||||
).is_ok() {
|
||||
let def_id = module.def_id().unwrap();
|
||||
found_traits.push(TraitCandidate { def_id: def_id, import_ids: smallvec![] });
|
||||
}
|
||||
}
|
||||
|
||||
ident.span = ident.span.modern();
|
||||
let mut search_module = self.current_module;
|
||||
loop {
|
||||
self.get_traits_in_module_containing_item(ident, ns, search_module, &mut found_traits);
|
||||
search_module = unwrap_or!(
|
||||
self.hygienic_lexical_parent(search_module, &mut ident.span), break
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(prelude) = self.prelude {
|
||||
if !search_module.no_implicit_prelude {
|
||||
self.get_traits_in_module_containing_item(ident, ns, prelude, &mut found_traits);
|
||||
}
|
||||
}
|
||||
|
||||
found_traits
|
||||
}
|
||||
|
||||
fn get_traits_in_module_containing_item(&mut self,
|
||||
ident: Ident,
|
||||
ns: Namespace,
|
||||
module: Module<'a>,
|
||||
found_traits: &mut Vec<TraitCandidate>) {
|
||||
assert!(ns == TypeNS || ns == ValueNS);
|
||||
let mut traits = module.traits.borrow_mut();
|
||||
if traits.is_none() {
|
||||
let mut collected_traits = Vec::new();
|
||||
module.for_each_child(|name, ns, binding| {
|
||||
if ns != TypeNS { return }
|
||||
match binding.res() {
|
||||
Res::Def(DefKind::Trait, _) |
|
||||
Res::Def(DefKind::TraitAlias, _) => collected_traits.push((name, binding)),
|
||||
_ => (),
|
||||
}
|
||||
});
|
||||
*traits = Some(collected_traits.into_boxed_slice());
|
||||
}
|
||||
|
||||
for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
|
||||
// Traits have pseudo-modules that can be used to search for the given ident.
|
||||
if let Some(module) = binding.module() {
|
||||
let mut ident = ident;
|
||||
if ident.span.glob_adjust(
|
||||
module.expansion,
|
||||
binding.span,
|
||||
).is_none() {
|
||||
continue
|
||||
}
|
||||
if self.resolve_ident_in_module_unadjusted(
|
||||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
ns,
|
||||
false,
|
||||
module.span,
|
||||
).is_ok() {
|
||||
let import_ids = self.find_transitive_imports(&binding.kind, trait_name);
|
||||
let trait_def_id = module.def_id().unwrap();
|
||||
found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
|
||||
}
|
||||
} else if let Res::Def(DefKind::TraitAlias, _) = binding.res() {
|
||||
// For now, just treat all trait aliases as possible candidates, since we don't
|
||||
// know if the ident is somewhere in the transitive bounds.
|
||||
let import_ids = self.find_transitive_imports(&binding.kind, trait_name);
|
||||
let trait_def_id = binding.res().def_id();
|
||||
found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
|
||||
} else {
|
||||
bug!("candidate is not trait or trait alias?")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_transitive_imports(&mut self, mut kind: &NameBindingKind<'_>,
|
||||
trait_name: Ident) -> SmallVec<[NodeId; 1]> {
|
||||
let mut import_ids = smallvec![];
|
||||
while let NameBindingKind::Import { directive, binding, .. } = kind {
|
||||
self.maybe_unused_trait_imports.insert(directive.id);
|
||||
self.add_to_glob_map(&directive, trait_name);
|
||||
import_ids.push(directive.id);
|
||||
kind = &binding.kind;
|
||||
};
|
||||
import_ids
|
||||
}
|
||||
|
||||
fn record_partial_res(&mut self, node_id: NodeId, resolution: PartialRes) {
|
||||
debug!("(recording res) recording {:?} for {}", resolution, node_id);
|
||||
if let Some(prev_res) = self.partial_res_map.insert(node_id, resolution) {
|
||||
@@ -4589,71 +2170,6 @@ fn record_partial_res(&mut self, node_id: NodeId, resolution: PartialRes) {
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility {
|
||||
match vis.node {
|
||||
ast::VisibilityKind::Public => ty::Visibility::Public,
|
||||
ast::VisibilityKind::Crate(..) => {
|
||||
ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
|
||||
}
|
||||
ast::VisibilityKind::Inherited => {
|
||||
ty::Visibility::Restricted(self.current_module.normal_ancestor_id)
|
||||
}
|
||||
ast::VisibilityKind::Restricted { ref path, id, .. } => {
|
||||
// For visibilities we are not ready to provide correct implementation of "uniform
|
||||
// paths" right now, so on 2018 edition we only allow module-relative paths for now.
|
||||
// On 2015 edition visibilities are resolved as crate-relative by default,
|
||||
// so we are prepending a root segment if necessary.
|
||||
let ident = path.segments.get(0).expect("empty path in visibility").ident;
|
||||
let crate_root = if ident.is_path_segment_keyword() {
|
||||
None
|
||||
} else if ident.span.rust_2018() {
|
||||
let msg = "relative paths are not supported in visibilities on 2018 edition";
|
||||
self.session.struct_span_err(ident.span, msg)
|
||||
.span_suggestion(
|
||||
path.span,
|
||||
"try",
|
||||
format!("crate::{}", path),
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
return ty::Visibility::Public;
|
||||
} else {
|
||||
let ctxt = ident.span.ctxt();
|
||||
Some(Segment::from_ident(Ident::new(
|
||||
kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ctxt)
|
||||
)))
|
||||
};
|
||||
|
||||
let segments = crate_root.into_iter()
|
||||
.chain(path.segments.iter().map(|seg| seg.into())).collect::<Vec<_>>();
|
||||
let res = self.smart_resolve_path_fragment(
|
||||
id,
|
||||
None,
|
||||
&segments,
|
||||
path.span,
|
||||
PathSource::Visibility,
|
||||
CrateLint::SimplePath(id),
|
||||
).base_res();
|
||||
if res == Res::Err {
|
||||
ty::Visibility::Public
|
||||
} else {
|
||||
let vis = ty::Visibility::Restricted(res.def_id());
|
||||
if self.is_accessible(vis) {
|
||||
vis
|
||||
} else {
|
||||
self.session.span_err(path.span, "visibilities can only be restricted \
|
||||
to ancestor modules");
|
||||
ty::Visibility::Public
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_accessible(&self, vis: ty::Visibility) -> bool {
|
||||
vis.is_accessible_from(self.current_module.normal_ancestor_id, self)
|
||||
}
|
||||
|
||||
fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
|
||||
vis.is_accessible_from(module.normal_ancestor_id, self)
|
||||
}
|
||||
@@ -5111,14 +2627,79 @@ fn extern_prelude_get(&mut self, ident: Ident, speculative: bool)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {
|
||||
namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper
|
||||
}
|
||||
/// Rustdoc uses this to resolve things in a recoverable way. `ResolutionError<'a>`
|
||||
/// isn't something that can be returned because it can't be made to live that long,
|
||||
/// and also it's a private type. Fortunately rustdoc doesn't need to know the error,
|
||||
/// just that an error occurred.
|
||||
// FIXME(Manishearth): intra-doc links won't get warned of epoch changes.
|
||||
pub fn resolve_str_path_error(
|
||||
&mut self, span: Span, path_str: &str, ns: Namespace, module_id: NodeId
|
||||
) -> Result<(ast::Path, Res), ()> {
|
||||
let path = if path_str.starts_with("::") {
|
||||
ast::Path {
|
||||
span,
|
||||
segments: iter::once(Ident::with_empty_ctxt(kw::PathRoot))
|
||||
.chain({
|
||||
path_str.split("::").skip(1).map(Ident::from_str)
|
||||
})
|
||||
.map(|i| self.new_ast_path_segment(i))
|
||||
.collect(),
|
||||
}
|
||||
} else {
|
||||
ast::Path {
|
||||
span,
|
||||
segments: path_str
|
||||
.split("::")
|
||||
.map(Ident::from_str)
|
||||
.map(|i| self.new_ast_path_segment(i))
|
||||
.collect(),
|
||||
}
|
||||
};
|
||||
let module = self.block_map.get(&module_id).copied().unwrap_or_else(|| {
|
||||
let def_id = self.definitions.local_def_id(module_id);
|
||||
self.module_map.get(&def_id).copied().unwrap_or(self.graph_root)
|
||||
});
|
||||
let parent_scope = &ParentScope { module, ..self.dummy_parent_scope() };
|
||||
let res = self.resolve_ast_path(&path, ns, parent_scope).map_err(|_| ())?;
|
||||
Ok((path, res))
|
||||
}
|
||||
|
||||
fn is_self_value(path: &[Segment], namespace: Namespace) -> bool {
|
||||
namespace == ValueNS && path.len() == 1 && path[0].ident.name == kw::SelfLower
|
||||
// Resolve a path passed from rustdoc or HIR lowering.
|
||||
fn resolve_ast_path(
|
||||
&mut self,
|
||||
path: &ast::Path,
|
||||
ns: Namespace,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
) -> Result<Res, (Span, ResolutionError<'a>)> {
|
||||
match self.resolve_path(
|
||||
&Segment::from_path(path), Some(ns), parent_scope, true, path.span, CrateLint::No
|
||||
) {
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
|
||||
Ok(module.res().unwrap()),
|
||||
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 =>
|
||||
Ok(path_res.base_res()),
|
||||
PathResult::NonModule(..) => {
|
||||
Err((path.span, ResolutionError::FailedToResolve {
|
||||
label: String::from("type-relative paths are not supported in this context"),
|
||||
suggestion: None,
|
||||
}))
|
||||
}
|
||||
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
|
||||
PathResult::Failed { span, label, suggestion, .. } => {
|
||||
Err((span, ResolutionError::FailedToResolve {
|
||||
label,
|
||||
suggestion,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn new_ast_path_segment(&self, ident: Ident) -> ast::PathSegment {
|
||||
let mut seg = ast::PathSegment::from_ident(ident);
|
||||
seg.id = self.session.next_node_id();
|
||||
seg
|
||||
}
|
||||
}
|
||||
|
||||
fn names_to_string(idents: &[Ident]) -> String {
|
||||
|
||||
+32
-107
@@ -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 @@ fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &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 @@ fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension) {
|
||||
}
|
||||
|
||||
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 @@ fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: ExpnId, for
|
||||
// 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 @@ fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: ExpnId, for
|
||||
}
|
||||
};
|
||||
|
||||
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 @@ pub fn resolve_macro_path(
|
||||
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 @@ struct Flags: u8 {
|
||||
}
|
||||
|
||||
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 @@ struct Flags: u8 {
|
||||
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 @@ struct Flags: u8 {
|
||||
ModuleOrUniformRoot::Module(root_module),
|
||||
ident,
|
||||
ns,
|
||||
None,
|
||||
parent_scope,
|
||||
record_used,
|
||||
path_span,
|
||||
);
|
||||
@@ -516,17 +500,16 @@ struct Flags: u8 {
|
||||
}
|
||||
}
|
||||
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 @@ struct Flags: u8 {
|
||||
ModuleOrUniformRoot::Module(prelude),
|
||||
ident,
|
||||
ns,
|
||||
parent_scope,
|
||||
false,
|
||||
path_span,
|
||||
) {
|
||||
@@ -710,9 +694,7 @@ struct Flags: u8 {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ pub fn finalize_current_module_macro_resolutions(&mut self) {
|
||||
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 @@ pub fn finalize_current_module_macro_resolutions(&mut self) {
|
||||
(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 @@ fn prohibit_imported_non_macro_attrs(&self, binding: Option<&'a NameBinding<'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::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::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 @@ pub(crate) fn binding(&self) -> Option<&'a NameBinding<'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 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
|
||||
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 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
|
||||
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 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
|
||||
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 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
|
||||
}
|
||||
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 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
|
||||
}
|
||||
// `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 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
|
||||
// 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 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
|
||||
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 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
|
||||
// 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 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
|
||||
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 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
|
||||
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 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
|
||||
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 @@ pub fn finalize_imports(&mut self) {
|
||||
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 @@ pub fn finalize_imports(&mut self) {
|
||||
|
||||
// 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 @@ pub fn finalize_imports(&mut self) {
|
||||
// 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 @@ fn throw_unresolved_import_error(
|
||||
(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 @@ fn throw_unresolved_import_error(
|
||||
/// 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 @@ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
|
||||
// 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 @@ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
|
||||
};
|
||||
|
||||
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 @@ fn finalize_import(
|
||||
&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 @@ fn finalize_import(
|
||||
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 @@ fn finalize_import(
|
||||
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 @@ fn finalize_import(
|
||||
// 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 @@ fn finalize_import(
|
||||
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 @@ fn finalize_import(
|
||||
};
|
||||
|
||||
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 @@ fn finalize_import(
|
||||
|
||||
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 @@ fn finalize_import(
|
||||
})
|
||||
} 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 @@ fn finalize_import(
|
||||
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 @@ fn finalize_import(
|
||||
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 @@ fn finalize_import(
|
||||
// 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 @@ fn finalize_import(
|
||||
// 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 @@ fn check_for_redundant_imports(
|
||||
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 @@ fn check_for_redundant_imports(
|
||||
|
||||
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 @@ fn check_for_redundant_imports(
|
||||
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 @@ fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'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 @@ fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'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 @@ fn finalize_resolutions_in(&mut self, module: Module<'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 @@ fn finalize_resolutions_in(&mut self, module: Module<'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 @@ fn finalize_resolutions_in(&mut self, module: Module<'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 @@ fn finalize_resolutions_in(&mut self, module: Module<'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 @@ fn finalize_resolutions_in(&mut self, module: Module<'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 @@ fn finalize_resolutions_in(&mut self, module: Module<'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 @@ fn resolve(&self,
|
||||
{
|
||||
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 @@ fn resolve(&self,
|
||||
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 @@ fn resolve(&self,
|
||||
.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(());
|
||||
}
|
||||
|
||||
@@ -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!();
|
||||
}
|
||||
@@ -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
-1
@@ -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`.
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user