resolve: Resolve multi-segment imports using in-scope resolution on 2018 edition
This commit is contained in:
parent
67feeebfad
commit
e6739fe274
@ -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()
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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() !=
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user