resolve: Make sure macros and imports are resolved in full parent scope
Slightly simplify `fn build_reduced_graph_for_use_tree`
This commit is contained in:
parent
acdbd0643c
commit
1f257bd022
@ -111,23 +111,23 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
|
||||
fn build_reduced_graph_for_use_tree(
|
||||
&mut self,
|
||||
root_use_tree: &ast::UseTree,
|
||||
root_id: NodeId,
|
||||
// This particular use tree
|
||||
use_tree: &ast::UseTree,
|
||||
id: NodeId,
|
||||
vis: ty::Visibility,
|
||||
parent_prefix: &[Segment],
|
||||
mut uniform_paths_canary_emitted: bool,
|
||||
nested: bool,
|
||||
item: &Item,
|
||||
mut uniform_paths_canary_emitted: 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={:?}, \
|
||||
uniform_paths_canary_emitted={}, \
|
||||
use_tree={:?}, nested={})",
|
||||
parent_prefix, uniform_paths_canary_emitted, use_tree, nested);
|
||||
|
||||
let is_prelude = attr::contains_name(&item.attrs, "prelude_import");
|
||||
let uniform_paths =
|
||||
self.session.rust_2018() &&
|
||||
self.session.features_untracked().uniform_paths;
|
||||
@ -215,8 +215,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
subclass,
|
||||
source.ident.span,
|
||||
id,
|
||||
root_use_tree.span,
|
||||
root_id,
|
||||
root_span,
|
||||
item.id,
|
||||
ty::Visibility::Invisible,
|
||||
parent_scope.clone(),
|
||||
true, // is_uniform_paths_canary
|
||||
@ -345,8 +345,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
subclass,
|
||||
use_tree.span,
|
||||
id,
|
||||
root_use_tree.span,
|
||||
root_id,
|
||||
root_span,
|
||||
item.id,
|
||||
vis,
|
||||
parent_scope,
|
||||
false, // is_uniform_paths_canary
|
||||
@ -354,7 +354,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
}
|
||||
ast::UseTreeKind::Glob => {
|
||||
let subclass = GlobImport {
|
||||
is_prelude,
|
||||
is_prelude: attr::contains_name(&item.attrs, "prelude_import"),
|
||||
max_vis: Cell::new(ty::Visibility::Invisible),
|
||||
};
|
||||
self.add_import_directive(
|
||||
@ -362,8 +362,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
subclass,
|
||||
use_tree.span,
|
||||
id,
|
||||
root_use_tree.span,
|
||||
root_id,
|
||||
root_span,
|
||||
item.id,
|
||||
vis,
|
||||
parent_scope,
|
||||
false, // is_uniform_paths_canary
|
||||
@ -394,16 +394,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
|
||||
for &(ref tree, id) in items {
|
||||
self.build_reduced_graph_for_use_tree(
|
||||
root_use_tree,
|
||||
root_id,
|
||||
tree,
|
||||
id,
|
||||
vis,
|
||||
&prefix,
|
||||
uniform_paths_canary_emitted,
|
||||
true,
|
||||
item,
|
||||
parent_scope.clone(),
|
||||
// This particular use tree
|
||||
tree, id, &prefix, true, uniform_paths_canary_emitted,
|
||||
// The whole `use` item
|
||||
parent_scope.clone(), item, vis, root_span,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -421,16 +415,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
match item.node {
|
||||
ItemKind::Use(ref use_tree) => {
|
||||
self.build_reduced_graph_for_use_tree(
|
||||
use_tree,
|
||||
item.id,
|
||||
use_tree,
|
||||
item.id,
|
||||
vis,
|
||||
&[],
|
||||
false, // uniform_paths_canary_emitted
|
||||
false,
|
||||
item,
|
||||
parent_scope,
|
||||
// This particular use tree
|
||||
use_tree, item.id, &[], false, false,
|
||||
// The whole `use` item
|
||||
parent_scope, item, vis, use_tree.span,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use {CrateLint, PathResult, Segment};
|
||||
use macros::ParentScope;
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
@ -23,7 +24,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||
pub(crate) fn make_path_suggestion(
|
||||
&mut self,
|
||||
span: Span,
|
||||
path: Vec<Segment>
|
||||
path: Vec<Segment>,
|
||||
parent_scope: &ParentScope<'b>,
|
||||
) -> Option<Vec<Segment>> {
|
||||
debug!("make_path_suggestion: span={:?} path={:?}", span, path);
|
||||
// If we don't have a path to suggest changes to, then return.
|
||||
@ -40,10 +42,12 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||
(Some(fst), Some(snd)) if !is_special(fst.ident) && !is_special(snd.ident) => {
|
||||
debug!("make_path_suggestion: fst={:?} snd={:?}", fst, snd);
|
||||
|
||||
self.make_missing_self_suggestion(span, path.clone())
|
||||
.or_else(|| self.make_missing_crate_suggestion(span, path.clone()))
|
||||
.or_else(|| self.make_missing_super_suggestion(span, path.clone()))
|
||||
.or_else(|| self.make_external_crate_suggestion(span, path))
|
||||
self.make_missing_self_suggestion(span, path.clone(), parent_scope)
|
||||
.or_else(|| self.make_missing_crate_suggestion(span, path.clone(),
|
||||
parent_scope))
|
||||
.or_else(|| self.make_missing_super_suggestion(span, path.clone(),
|
||||
parent_scope))
|
||||
.or_else(|| self.make_external_crate_suggestion(span, path, parent_scope))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
@ -59,11 +63,12 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||
fn make_missing_self_suggestion(
|
||||
&mut self,
|
||||
span: Span,
|
||||
mut path: Vec<Segment>
|
||||
mut path: Vec<Segment>,
|
||||
parent_scope: &ParentScope<'b>,
|
||||
) -> Option<Vec<Segment>> {
|
||||
// Replace first ident with `self` and check if that is valid.
|
||||
path[0].ident.name = keywords::SelfValue.name();
|
||||
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
|
||||
let result = self.resolve_path(None, &path, None, parent_scope, false, span, CrateLint::No);
|
||||
debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
|
||||
if let PathResult::Module(..) = result {
|
||||
Some(path)
|
||||
@ -82,11 +87,12 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||
fn make_missing_crate_suggestion(
|
||||
&mut self,
|
||||
span: Span,
|
||||
mut path: Vec<Segment>
|
||||
mut path: Vec<Segment>,
|
||||
parent_scope: &ParentScope<'b>,
|
||||
) -> Option<Vec<Segment>> {
|
||||
// Replace first ident with `crate` and check if that is valid.
|
||||
path[0].ident.name = keywords::Crate.name();
|
||||
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
|
||||
let result = self.resolve_path(None, &path, None, parent_scope, false, span, CrateLint::No);
|
||||
debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result);
|
||||
if let PathResult::Module(..) = result {
|
||||
Some(path)
|
||||
@ -105,11 +111,12 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||
fn make_missing_super_suggestion(
|
||||
&mut self,
|
||||
span: Span,
|
||||
mut path: Vec<Segment>
|
||||
mut path: Vec<Segment>,
|
||||
parent_scope: &ParentScope<'b>,
|
||||
) -> Option<Vec<Segment>> {
|
||||
// Replace first ident with `crate` and check if that is valid.
|
||||
path[0].ident.name = keywords::Super.name();
|
||||
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
|
||||
let result = self.resolve_path(None, &path, None, parent_scope, false, span, CrateLint::No);
|
||||
debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result);
|
||||
if let PathResult::Module(..) = result {
|
||||
Some(path)
|
||||
@ -131,7 +138,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||
fn make_external_crate_suggestion(
|
||||
&mut self,
|
||||
span: Span,
|
||||
mut path: Vec<Segment>
|
||||
mut path: Vec<Segment>,
|
||||
parent_scope: &ParentScope<'b>,
|
||||
) -> Option<Vec<Segment>> {
|
||||
// Need to clone else we can't call `resolve_path` without a borrow error. We also store
|
||||
// into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic)
|
||||
@ -149,7 +157,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||
// Replace the first after root (a placeholder we inserted) with a crate name
|
||||
// and check if that is valid.
|
||||
path[1].ident.name = *name;
|
||||
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
|
||||
let result =
|
||||
self.resolve_path(None, &path, None, parent_scope, false, span, CrateLint::No);
|
||||
debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
|
||||
name, path, result);
|
||||
if let PathResult::Module(..) = result {
|
||||
|
@ -1054,7 +1054,7 @@ pub struct ModuleData<'a> {
|
||||
resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
|
||||
legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>,
|
||||
Option<&'a NameBinding<'a>>)>>,
|
||||
macro_resolutions: RefCell<Vec<(Box<[Ident]>, Span)>>,
|
||||
macro_resolutions: RefCell<Vec<(Vec<Segment>, ParentScope<'a>, Span)>>,
|
||||
builtin_attrs: RefCell<Vec<(Ident, ParentScope<'a>)>>,
|
||||
|
||||
// Macro invocations that can expand into items in this module.
|
||||
@ -1668,22 +1668,15 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
|
||||
let segments = &path.segments;
|
||||
let path = Segment::from_path(&path);
|
||||
// FIXME (Manishearth): Intra doc links won't get warned of epoch changes
|
||||
let def = match self.resolve_path(None, &path, Some(namespace), true, span, CrateLint::No) {
|
||||
let def = match self.resolve_path_without_parent_scope(None, &path, Some(namespace),
|
||||
true, span, CrateLint::No) {
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
|
||||
module.def().unwrap(),
|
||||
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 =>
|
||||
path_res.base_def(),
|
||||
PathResult::NonModule(..) => {
|
||||
if let PathResult::Failed(span, msg, _) = self.resolve_path(
|
||||
None,
|
||||
&path,
|
||||
None,
|
||||
true,
|
||||
span,
|
||||
CrateLint::No,
|
||||
) {
|
||||
error_callback(self, span, ResolutionError::FailedToResolve(&msg));
|
||||
}
|
||||
let msg = "type-relative paths are not supported in this context";
|
||||
error_callback(self, span, ResolutionError::FailedToResolve(msg));
|
||||
Def::Err
|
||||
}
|
||||
PathResult::Module(ModuleOrUniformRoot::UniformRoot(_)) |
|
||||
@ -2530,10 +2523,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||
new_id = Some(def.def_id());
|
||||
let span = trait_ref.path.span;
|
||||
if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
|
||||
self.resolve_path(
|
||||
self.resolve_path_without_parent_scope(
|
||||
None,
|
||||
&path,
|
||||
None,
|
||||
Some(TypeNS),
|
||||
false,
|
||||
span,
|
||||
CrateLint::SimplePath(trait_ref.ref_id),
|
||||
@ -3055,8 +3048,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||
(String::new(), "the crate root".to_string())
|
||||
} else {
|
||||
let mod_path = &path[..path.len() - 1];
|
||||
let mod_prefix = match this.resolve_path(None, mod_path, Some(TypeNS),
|
||||
false, span, CrateLint::No) {
|
||||
let mod_prefix = match this.resolve_path_without_parent_scope(
|
||||
None, mod_path, Some(TypeNS), false, span, CrateLint::No
|
||||
) {
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
|
||||
module.def(),
|
||||
_ => None,
|
||||
@ -3540,7 +3534,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||
));
|
||||
}
|
||||
|
||||
let result = match self.resolve_path(
|
||||
let result = match self.resolve_path_without_parent_scope(
|
||||
None,
|
||||
&path,
|
||||
Some(ns),
|
||||
@ -3587,7 +3581,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||
path[0].ident.name != keywords::CrateRoot.name() &&
|
||||
path[0].ident.name != keywords::DollarCrate.name() {
|
||||
let unqualified_result = {
|
||||
match self.resolve_path(
|
||||
match self.resolve_path_without_parent_scope(
|
||||
None,
|
||||
&[*path.last().unwrap()],
|
||||
Some(ns),
|
||||
@ -3610,7 +3604,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||
Some(result)
|
||||
}
|
||||
|
||||
fn resolve_path(
|
||||
fn resolve_path_without_parent_scope(
|
||||
&mut self,
|
||||
base_module: Option<ModuleOrUniformRoot<'a>>,
|
||||
path: &[Segment],
|
||||
@ -3619,12 +3613,15 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||
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_with_parent_scope(base_module, path, opt_ns, &parent_scope,
|
||||
self.resolve_path(base_module, path, opt_ns, &parent_scope,
|
||||
record_used, path_span, crate_lint)
|
||||
}
|
||||
|
||||
fn resolve_path_with_parent_scope(
|
||||
fn resolve_path(
|
||||
&mut self,
|
||||
base_module: Option<ModuleOrUniformRoot<'a>>,
|
||||
path: &[Segment],
|
||||
@ -3820,7 +3817,6 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||
PathResult::Module(module.unwrap_or_else(|| {
|
||||
span_bug!(path_span, "resolve_path: empty(?) path {:?} has no module", path);
|
||||
}))
|
||||
|
||||
}
|
||||
|
||||
fn lint_if_path_starts_with_module(
|
||||
@ -4104,8 +4100,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||
} else {
|
||||
// Search in module.
|
||||
let mod_path = &path[..path.len() - 1];
|
||||
if let PathResult::Module(module) = self.resolve_path(None, mod_path, Some(TypeNS),
|
||||
false, span, CrateLint::No) {
|
||||
if let PathResult::Module(module) = self.resolve_path_without_parent_scope(
|
||||
None, mod_path, Some(TypeNS), false, span, CrateLint::No
|
||||
) {
|
||||
if let ModuleOrUniformRoot::Module(module) = module {
|
||||
add_module_candidates(module, &mut names);
|
||||
}
|
||||
|
@ -462,7 +462,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
parent_scope: &ParentScope<'a>,
|
||||
force: bool,
|
||||
) -> Result<Def, Determinacy> {
|
||||
let span = path.span;
|
||||
let path_span = path.span;
|
||||
let mut path = Segment::from_path(path);
|
||||
|
||||
// Possibly apply the macro helper hack
|
||||
@ -474,15 +474,15 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
}
|
||||
|
||||
if path.len() > 1 {
|
||||
let def = match self.resolve_path_with_parent_scope(None, &path, Some(MacroNS),
|
||||
parent_scope, false, span,
|
||||
CrateLint::No) {
|
||||
let def = match self.resolve_path(None, &path, Some(MacroNS), parent_scope,
|
||||
false, path_span, CrateLint::No) {
|
||||
PathResult::NonModule(path_res) => match path_res.base_def() {
|
||||
Def::Err => Err(Determinacy::Determined),
|
||||
def @ _ => {
|
||||
if path_res.unresolved_segments() > 0 {
|
||||
self.found_unresolved_macro = true;
|
||||
self.session.span_err(span, "fail to resolve non-ident macro path");
|
||||
self.session.span_err(path_span,
|
||||
"fail to resolve non-ident macro path");
|
||||
Err(Determinacy::Determined)
|
||||
} else {
|
||||
Ok(def)
|
||||
@ -498,16 +498,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
};
|
||||
|
||||
parent_scope.module.macro_resolutions.borrow_mut()
|
||||
.push((path
|
||||
.iter()
|
||||
.map(|seg| seg.ident)
|
||||
.collect::<Vec<Ident>>()
|
||||
.into_boxed_slice(), span));
|
||||
.push((path, parent_scope.clone(), path_span));
|
||||
|
||||
def
|
||||
} else {
|
||||
let binding = self.early_resolve_ident_in_lexical_scope(
|
||||
path[0].ident, MacroNS, Some(kind), parent_scope, false, force, span
|
||||
path[0].ident, MacroNS, Some(kind), parent_scope, false, force, path_span
|
||||
);
|
||||
match binding {
|
||||
Ok(..) => {}
|
||||
@ -851,9 +847,14 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
|
||||
pub fn finalize_current_module_macro_resolutions(&mut self) {
|
||||
let module = self.current_module;
|
||||
for &(ref path, span) in module.macro_resolutions.borrow().iter() {
|
||||
let path: Vec<_> = path.iter().map(|&ident| Segment::from_ident(ident)).collect();
|
||||
match self.resolve_path(None, &path, Some(MacroNS), true, span, CrateLint::No) {
|
||||
|
||||
let macro_resolutions =
|
||||
mem::replace(&mut *module.macro_resolutions.borrow_mut(), Vec::new());
|
||||
for (mut path, parent_scope, path_span) in macro_resolutions {
|
||||
// FIXME: Path resolution will ICE if segment IDs present.
|
||||
for seg in &mut path { seg.id = None; }
|
||||
match self.resolve_path(None, &path, Some(MacroNS), &parent_scope,
|
||||
true, path_span, CrateLint::No) {
|
||||
PathResult::NonModule(_) => {},
|
||||
PathResult::Failed(span, msg, _) => {
|
||||
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
|
||||
|
@ -877,6 +877,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||
}),
|
||||
&directive.module_path[..],
|
||||
None,
|
||||
&directive.parent_scope,
|
||||
false,
|
||||
directive.span,
|
||||
directive.crate_lint(),
|
||||
@ -956,6 +957,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||
}),
|
||||
&module_path,
|
||||
None,
|
||||
&directive.parent_scope,
|
||||
true,
|
||||
span,
|
||||
directive.crate_lint(),
|
||||
@ -968,7 +970,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||
}
|
||||
PathResult::Failed(span, msg, true) => {
|
||||
return if let Some(suggested_path) = self.make_path_suggestion(
|
||||
span, module_path.clone()
|
||||
span, module_path.clone(), &directive.parent_scope
|
||||
) {
|
||||
Some((
|
||||
span,
|
||||
|
Loading…
x
Reference in New Issue
Block a user