resolve: Resolve multi-segment imports using in-scope resolution on 2018 edition

This commit is contained in:
Vadim Petrochenkov 2018-11-03 22:02:36 +03:00
parent 67feeebfad
commit e6739fe274
5 changed files with 46 additions and 65 deletions

View File

@ -125,36 +125,24 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
debug!("build_reduced_graph_for_use_tree(parent_prefix={:?}, use_tree={:?}, nested={})",
parent_prefix, use_tree, nested);
let uniform_paths =
self.session.rust_2018() &&
self.session.features_untracked().uniform_paths;
let mut prefix_iter = parent_prefix.iter().cloned()
.chain(use_tree.prefix.segments.iter().map(|seg| seg.ident)).peekable();
let prefix_iter = || parent_prefix.iter().cloned()
.chain(use_tree.prefix.segments.iter().map(|seg| seg.into()));
let prefix_start = prefix_iter().next();
let starts_with_non_keyword = prefix_start.map_or(false, |seg| {
!seg.ident.is_path_segment_keyword()
});
// Imports are resolved as global by default, prepend `CrateRoot`,
// unless `#![feature(uniform_paths)]` is enabled.
let inject_crate_root =
!uniform_paths &&
match use_tree.kind {
// HACK(eddyb) special-case `use *` to mean `use ::*`.
ast::UseTreeKind::Glob if prefix_start.is_none() => true,
_ => starts_with_non_keyword,
};
let root = if inject_crate_root {
let span = use_tree.prefix.span.shrink_to_lo();
Some(Segment::from_ident(Ident::new(keywords::CrateRoot.name(), span)))
// 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 = if !self.session.rust_2018() &&
prefix_iter.peek().map_or(is_glob, |ident| !ident.is_path_segment_keyword()) {
Some(Ident::new(keywords::CrateRoot.name(), use_tree.prefix.span.shrink_to_lo()))
} else {
None
};
let prefix: Vec<_> = root.into_iter().chain(prefix_iter()).collect();
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 == keywords::CrateRoot.name()

View File

@ -68,7 +68,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
) -> Option<(Vec<Segment>, Option<String>)> {
// 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, parent_scope, false, span, CrateLint::No);
let result = self.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, None))
@ -92,7 +92,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
) -> Option<(Vec<Segment>, Option<String>)> {
// 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, parent_scope, false, span, CrateLint::No);
let result = self.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((
@ -123,7 +123,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
) -> Option<(Vec<Segment>, Option<String>)> {
// 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, parent_scope, false, span, CrateLint::No);
let result = self.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, None))
@ -164,8 +164,7 @@ 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, parent_scope, false, span, CrateLint::No);
let result = self.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 {

View File

@ -1661,8 +1661,8 @@ 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_without_parent_scope(None, &path, Some(namespace),
true, span, CrateLint::No) {
match self.resolve_path_without_parent_scope(&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 =>
@ -2466,7 +2466,6 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
let span = trait_ref.path.span;
if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
self.resolve_path_without_parent_scope(
None,
&path,
Some(TypeNS),
false,
@ -2991,7 +2990,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
} else {
let mod_path = &path[..path.len() - 1];
let mod_prefix = match this.resolve_path_without_parent_scope(
None, mod_path, Some(TypeNS), false, span, CrateLint::No
mod_path, Some(TypeNS), false, span, CrateLint::No
) {
PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
module.def(),
@ -3480,7 +3479,6 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
}
let result = match self.resolve_path_without_parent_scope(
None,
&path,
Some(ns),
true,
@ -3527,7 +3525,6 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
path[0].ident.name != keywords::DollarCrate.name() {
let unqualified_result = {
match self.resolve_path_without_parent_scope(
None,
&[*path.last().unwrap()],
Some(ns),
false,
@ -3551,9 +3548,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
fn resolve_path_without_parent_scope(
&mut self,
base_module: Option<ModuleOrUniformRoot<'a>>,
path: &[Segment],
opt_ns: Option<Namespace>, // `None` indicates a module path
opt_ns: Option<Namespace>, // `None` indicates a module path in import
record_used: bool,
path_span: Span,
crate_lint: CrateLint,
@ -3562,21 +3558,19 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
// 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(base_module, path, opt_ns, &parent_scope,
record_used, path_span, crate_lint)
self.resolve_path(path, opt_ns, &parent_scope, record_used, path_span, crate_lint)
}
fn resolve_path(
&mut self,
base_module: Option<ModuleOrUniformRoot<'a>>,
path: &[Segment],
opt_ns: Option<Namespace>, // `None` indicates a module path
opt_ns: Option<Namespace>, // `None` indicates a module path in import
parent_scope: &ParentScope<'a>,
record_used: bool,
path_span: Span,
crate_lint: CrateLint,
) -> PathResult<'a> {
let mut module = base_module;
let mut module = None;
let mut allow_super = true;
let mut second_binding = None;
self.current_module = parent_scope.module;
@ -3673,10 +3667,11 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
let binding = if let Some(module) = module {
self.resolve_ident_in_module(module, ident, ns, record_used, path_span)
} else if opt_ns == Some(MacroNS) {
} else if opt_ns.is_none() || opt_ns == Some(MacroNS) {
assert!(ns == TypeNS);
self.early_resolve_ident_in_lexical_scope(ident, ns, None, parent_scope,
record_used, record_used, path_span)
self.early_resolve_ident_in_lexical_scope(ident, ns, None, opt_ns.is_none(),
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 };
@ -3763,9 +3758,11 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
self.lint_if_path_starts_with_module(crate_lint, path, path_span, second_binding);
PathResult::Module(module.unwrap_or_else(|| {
span_bug!(path_span, "resolve_path: empty(?) path {:?} has no module", path);
}))
PathResult::Module(match module {
Some(module) => module,
None if path.is_empty() => ModuleOrUniformRoot::UniformRoot(keywords::Invalid.name()),
_ => span_bug!(path_span, "resolve_path: non-empty path `{:?}` has no module", path),
})
}
fn lint_if_path_starts_with_module(
@ -4050,7 +4047,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
// Search in module.
let mod_path = &path[..path.len() - 1];
if let PathResult::Module(module) = self.resolve_path_without_parent_scope(
None, mod_path, Some(TypeNS), false, span, CrateLint::No
mod_path, Some(TypeNS), false, span, CrateLint::No
) {
if let ModuleOrUniformRoot::Module(module) = module {
add_module_candidates(module, &mut names);

View File

@ -477,7 +477,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
}
if path.len() > 1 {
let def = match self.resolve_path(None, &path, Some(MacroNS), parent_scope,
let def = match self.resolve_path(&path, Some(MacroNS), parent_scope,
false, path_span, CrateLint::No) {
PathResult::NonModule(path_res) => match path_res.base_def() {
Def::Err => Err(Determinacy::Determined),
@ -506,7 +506,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
def
} else {
let binding = self.early_resolve_ident_in_lexical_scope(
path[0].ident, MacroNS, Some(kind), parent_scope, false, force, path_span
path[0].ident, MacroNS, Some(kind), false, parent_scope, false, force, path_span
);
match binding {
Ok(..) => {}
@ -525,12 +525,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
// This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during
// expansion and import resolution (perhaps they can be merged in the future).
// The function is used for resolving initial segments of macro paths (e.g. `foo` in
// `foo::bar!(); or `foo!();`) and can be used for "uniform path" imports in the future.
// `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition.
crate fn early_resolve_ident_in_lexical_scope(
&mut self,
mut ident: Ident,
ns: Namespace,
kind: Option<MacroKind>,
macro_kind: Option<MacroKind>,
is_import: bool,
parent_scope: &ParentScope<'a>,
record_used: bool,
force: bool,
@ -604,6 +605,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
}
assert!(force || !record_used); // `record_used` implies `force`
assert!(macro_kind.is_none() || !is_import); // `is_import` implies no macro kind
ident = ident.modern();
// This is *the* result, resolution from the scope closest to the resolved identifier.
@ -792,7 +794,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
match result {
Ok((binding, flags, ambig_flags)) => {
if sub_namespace_mismatch(kind, binding.macro_kind()) {
if sub_namespace_mismatch(macro_kind, binding.macro_kind()) {
continue_search!();
}
@ -804,7 +806,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
= innermost_result {
// Found another solution, if the first one was "weak", report an error.
if binding.def() != innermost_binding.def() &&
(innermost_binding.is_glob_import() ||
(is_import ||
innermost_binding.is_glob_import() ||
innermost_binding.may_appear_after(parent_scope.expansion, binding) ||
innermost_flags.intersects(ambig_flags) ||
flags.intersects(innermost_ambig_flags) ||
@ -838,7 +841,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
}
let determinacy = Determinacy::determined(force);
if determinacy == Determinacy::Determined && kind == Some(MacroKind::Attr) {
if determinacy == Determinacy::Determined && macro_kind == Some(MacroKind::Attr) {
// For single-segment attributes interpret determinate "no resolution" as a custom
// attribute. (Lexical resolution implies the first segment and attr kind should imply
// the last segment, so we are certainly working with a single-segment attribute here.)
@ -860,7 +863,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
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,
match self.resolve_path(&path, Some(MacroNS), &parent_scope,
true, path_span, CrateLint::No) {
PathResult::NonModule(_) => {},
PathResult::Failed(span, msg, _) => {
@ -874,7 +877,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
mem::replace(&mut *module.legacy_macro_resolutions.borrow_mut(), Vec::new());
for (ident, kind, parent_scope, initial_binding) in legacy_macro_resolutions {
let binding = self.early_resolve_ident_in_lexical_scope(
ident, MacroNS, Some(kind), &parent_scope, true, true, ident.span
ident, MacroNS, Some(kind), false, &parent_scope, true, true, ident.span
);
match binding {
Ok(binding) => {
@ -915,7 +918,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
let builtin_attrs = mem::replace(&mut *module.builtin_attrs.borrow_mut(), Vec::new());
for (ident, parent_scope) in builtin_attrs {
let binding = self.early_resolve_ident_in_lexical_scope(
ident, MacroNS, Some(MacroKind::Attr), &parent_scope, true, true, ident.span
ident, MacroNS, Some(MacroKind::Attr), false, &parent_scope, true, true, ident.span
);
if let Ok(binding) = binding {
if binding.def_ignoring_ambiguity() !=

View File

@ -152,10 +152,6 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
let can_be_relative = !ident.is_path_segment_keyword() &&
root == keywords::Invalid.name();
if can_be_relative {
// Relative paths should only get here if the feature-gate is on.
assert!(self.session.rust_2018() &&
self.session.features_untracked().uniform_paths);
// Try first to resolve relatively.
let mut ctxt = ident.span.ctxt().modern();
let self_module = self.resolve_self(&mut ctxt, self.current_module);
@ -750,7 +746,6 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
// while resolving its module path.
directive.vis.set(ty::Visibility::Invisible);
let result = self.resolve_path(
Some(ModuleOrUniformRoot::UniformRoot(keywords::Invalid.name())),
&directive.module_path[..],
None,
&directive.parent_scope,
@ -829,7 +824,6 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
let ImportDirective { ref module_path, span, .. } = *directive;
let module_result = self.resolve_path(
Some(ModuleOrUniformRoot::UniformRoot(keywords::Invalid.name())),
&module_path,
None,
&directive.parent_scope,