resolve: Move some common code into the scope visitor

This commit is contained in:
Vadim Petrochenkov 2019-07-14 23:04:51 +03:00
parent 329c05251a
commit 3845a08a55
3 changed files with 116 additions and 144 deletions

View file

@ -562,19 +562,10 @@ impl<'a> Resolver<'a> {
&mut self,
scope_set: ScopeSet,
parent_scope: &ParentScope<'a>,
orig_ident: Ident,
ident: Ident,
filter_fn: &impl Fn(Res) -> bool,
) -> Option<TypoSuggestion> {
let ident = orig_ident.modern();
let rust_2015 = orig_ident.span.rust_2015();
let is_absolute_path = match scope_set {
ScopeSet::AbsolutePath(..) => true,
_ => false,
};
let mut suggestions = Vec::new();
let mut use_prelude = !parent_scope.module.no_implicit_prelude;
self.visit_scopes(scope_set, parent_scope, ident, |this, scope, _| {
match scope {
Scope::DeriveHelpers => {
@ -603,26 +594,22 @@ impl<'a> Resolver<'a> {
}
}
Scope::CrateRoot => {
let root_ident = Ident::new(kw::PathRoot, orig_ident.span);
let root_ident = Ident::new(kw::PathRoot, ident.span);
let root_module = this.resolve_crate_root(root_ident);
add_module_candidates(root_module, &mut suggestions, filter_fn);
}
Scope::Module(module) => {
use_prelude = !module.no_implicit_prelude;
add_module_candidates(module, &mut suggestions, filter_fn);
}
Scope::MacroUsePrelude => {
if use_prelude || rust_2015 {
let macro_use_prelude = &this.macro_use_prelude;
suggestions.extend(macro_use_prelude.iter().filter_map(|(name, binding)| {
let res = binding.res();
if filter_fn(res) {
Some(TypoSuggestion::from_res(*name, res))
} else {
None
}
}));
}
suggestions.extend(this.macro_use_prelude.iter().filter_map(|(name, binding)| {
let res = binding.res();
if filter_fn(res) {
Some(TypoSuggestion::from_res(*name, res))
} else {
None
}
}));
}
Scope::BuiltinMacros => {
suggestions.extend(this.builtin_macros.iter().filter_map(|(name, binding)| {
@ -643,41 +630,33 @@ impl<'a> Resolver<'a> {
}
}
Scope::LegacyPluginHelpers => {
if use_prelude || rust_2015 {
let res = Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper);
if filter_fn(res) {
let plugin_attributes = this.session.plugin_attributes.borrow();
suggestions.extend(plugin_attributes.iter().map(|(name, _)| {
TypoSuggestion::from_res(*name, res)
}));
}
}
}
Scope::ExternPrelude => {
if use_prelude || is_absolute_path {
suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
let res = Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX));
if filter_fn(res) {
Some(TypoSuggestion::from_res(ident.name, res))
} else {
None
}
}));
}
}
Scope::ToolPrelude => {
if use_prelude {
let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
suggestions.extend(KNOWN_TOOLS.iter().map(|name| {
let res = Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper);
if filter_fn(res) {
let plugin_attributes = this.session.plugin_attributes.borrow();
suggestions.extend(plugin_attributes.iter().map(|(name, _)| {
TypoSuggestion::from_res(*name, res)
}));
}
}
Scope::StdLibPrelude => {
if use_prelude {
if let Some(prelude) = this.prelude {
add_module_candidates(prelude, &mut suggestions, filter_fn);
Scope::ExternPrelude => {
suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
let res = Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX));
if filter_fn(res) {
Some(TypoSuggestion::from_res(ident.name, res))
} else {
None
}
}));
}
Scope::ToolPrelude => {
let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
suggestions.extend(KNOWN_TOOLS.iter().map(|name| {
TypoSuggestion::from_res(*name, res)
}));
}
Scope::StdLibPrelude => {
if let Some(prelude) = this.prelude {
add_module_candidates(prelude, &mut suggestions, filter_fn);
}
}
Scope::BuiltinTypes => {

View file

@ -2145,7 +2145,7 @@ impl<'a> Resolver<'a> {
&mut self,
scope_set: ScopeSet,
parent_scope: &ParentScope<'a>,
mut ident: Ident,
ident: Ident,
mut visitor: impl FnMut(&mut Self, Scope<'a>, Ident) -> Option<T>,
) -> Option<T> {
// General principles:
@ -2192,6 +2192,7 @@ impl<'a> Resolver<'a> {
// but introduced by legacy plugins using `register_attribute`. Priority is somewhere
// in prelude, not sure where exactly (creates ambiguities with any other prelude names).
let rust_2015 = ident.span.rust_2015();
let (ns, is_absolute_path) = match scope_set {
ScopeSet::Import(ns) => (ns, false),
ScopeSet::AbsolutePath(ns) => (ns, true),
@ -2203,10 +2204,29 @@ impl<'a> Resolver<'a> {
TypeNS | ValueNS => Scope::Module(parent_scope.module),
MacroNS => Scope::DeriveHelpers,
};
let mut ident = ident.modern();
let mut use_prelude = !parent_scope.module.no_implicit_prelude;
loop {
if let break_result @ Some(..) = visitor(self, scope, ident) {
return break_result;
let visit = match scope {
Scope::DeriveHelpers => true,
Scope::MacroRules(..) => true,
Scope::CrateRoot => true,
Scope::Module(..) => true,
Scope::MacroUsePrelude => use_prelude || rust_2015,
Scope::BuiltinMacros => true,
Scope::BuiltinAttrs => true,
Scope::LegacyPluginHelpers => use_prelude || rust_2015,
Scope::ExternPrelude => use_prelude || is_absolute_path,
Scope::ToolPrelude => use_prelude,
Scope::StdLibPrelude => use_prelude,
Scope::BuiltinTypes => true,
};
if visit {
if let break_result @ Some(..) = visitor(self, scope, ident) {
return break_result;
}
}
scope = match scope {
@ -2229,6 +2249,7 @@ impl<'a> Resolver<'a> {
ValueNS | MacroNS => break,
}
Scope::Module(module) => {
use_prelude = !module.no_implicit_prelude;
match self.hygienic_lexical_parent(module, &mut ident.span) {
Some(parent_module) => Scope::Module(parent_module),
None => {

View file

@ -417,19 +417,17 @@ impl<'a> Resolver<'a> {
}
assert!(force || !record_used); // `record_used` implies `force`
let ident = orig_ident.modern();
// Make sure `self`, `super` etc produce an error when passed to here.
if ident.is_path_segment_keyword() {
if orig_ident.is_path_segment_keyword() {
return Err(Determinacy::Determined);
}
let rust_2015 = orig_ident.span.rust_2015();
let (ns, macro_kind, is_import, is_absolute_path) = match scope_set {
ScopeSet::Import(ns) => (ns, None, true, false),
ScopeSet::AbsolutePath(ns) => (ns, None, false, true),
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false, false),
ScopeSet::Module => (TypeNS, None, false, false),
let (ns, macro_kind, is_import) = match scope_set {
ScopeSet::Import(ns) => (ns, None, true),
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.
@ -444,11 +442,11 @@ impl<'a> Resolver<'a> {
// So we have to save the innermost solution and continue searching in outer scopes
// to detect potential ambiguities.
let mut innermost_result: Option<(&NameBinding<'_>, Flags)> = None;
let mut use_prelude = !parent_scope.module.no_implicit_prelude;
let mut determinacy = Determinacy::Determined;
// Go through all the scopes and try to resolve the name.
let break_result = self.visit_scopes(scope_set, parent_scope, ident, |this, scope, ident| {
let break_result =
self.visit_scopes(scope_set, parent_scope, orig_ident, |this, scope, ident| {
let result = match scope {
Scope::DeriveHelpers => {
let mut result = Err(Determinacy::Determined);
@ -478,11 +476,11 @@ impl<'a> Resolver<'a> {
_ => Err(Determinacy::Determined),
}
Scope::CrateRoot => {
let root_ident = Ident::new(kw::PathRoot, orig_ident.span);
let root_ident = Ident::new(kw::PathRoot, ident.span);
let root_module = this.resolve_crate_root(root_ident);
let binding = this.resolve_ident_in_module_ext(
ModuleOrUniformRoot::Module(root_module),
orig_ident,
ident,
ns,
None,
record_used,
@ -498,7 +496,6 @@ impl<'a> Resolver<'a> {
}
}
Scope::Module(module) => {
use_prelude = !module.no_implicit_prelude;
let orig_current_module = mem::replace(&mut this.current_module, module);
let binding = this.resolve_ident_in_module_unadjusted_ext(
ModuleOrUniformRoot::Module(module),
@ -528,94 +525,69 @@ impl<'a> Resolver<'a> {
Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
}
}
Scope::MacroUsePrelude => {
if use_prelude || rust_2015 {
match this.macro_use_prelude.get(&ident.name).cloned() {
Some(binding) =>
Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)),
None => Err(Determinacy::determined(
this.graph_root.unresolved_invocations.borrow().is_empty()
))
}
} else {
Err(Determinacy::Determined)
}
Scope::MacroUsePrelude => match this.macro_use_prelude.get(&ident.name).cloned() {
Some(binding) => Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)),
None => Err(Determinacy::determined(
this.graph_root.unresolved_invocations.borrow().is_empty()
))
}
Scope::BuiltinMacros => {
match this.builtin_macros.get(&ident.name).cloned() {
Some(binding) => Ok((binding, Flags::PRELUDE)),
None => Err(Determinacy::Determined),
}
Scope::BuiltinMacros => match this.builtin_macros.get(&ident.name).cloned() {
Some(binding) => Ok((binding, Flags::PRELUDE)),
None => Err(Determinacy::Determined),
}
Scope::BuiltinAttrs => {
if is_builtin_attr_name(ident.name) {
let binding = (Res::NonMacroAttr(NonMacroAttrKind::Builtin),
ty::Visibility::Public, DUMMY_SP, Mark::root())
.to_name_binding(this.arenas);
Ok((binding, Flags::PRELUDE))
} else {
Err(Determinacy::Determined)
}
Scope::BuiltinAttrs => if is_builtin_attr_name(ident.name) {
let binding = (Res::NonMacroAttr(NonMacroAttrKind::Builtin),
ty::Visibility::Public, DUMMY_SP, Mark::root())
.to_name_binding(this.arenas);
Ok((binding, Flags::PRELUDE))
} else {
Err(Determinacy::Determined)
}
Scope::LegacyPluginHelpers => {
if (use_prelude || rust_2015) &&
this.session.plugin_attributes.borrow().iter()
Scope::LegacyPluginHelpers => if this.session.plugin_attributes.borrow().iter()
.any(|(name, _)| ident.name == *name) {
let binding = (Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),
ty::Visibility::Public, DUMMY_SP, Mark::root())
.to_name_binding(this.arenas);
Ok((binding, Flags::PRELUDE))
} else {
Err(Determinacy::Determined)
}
let binding = (Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),
ty::Visibility::Public, DUMMY_SP, Mark::root())
.to_name_binding(this.arenas);
Ok((binding, Flags::PRELUDE))
} else {
Err(Determinacy::Determined)
}
Scope::ExternPrelude => {
if use_prelude || is_absolute_path {
match this.extern_prelude_get(ident, !record_used) {
Some(binding) => Ok((binding, Flags::PRELUDE)),
None => Err(Determinacy::determined(
this.graph_root.unresolved_invocations.borrow().is_empty()
)),
}
} else {
Err(Determinacy::Determined)
}
Scope::ExternPrelude => match this.extern_prelude_get(ident, !record_used) {
Some(binding) => Ok((binding, Flags::PRELUDE)),
None => Err(Determinacy::determined(
this.graph_root.unresolved_invocations.borrow().is_empty()
)),
}
Scope::ToolPrelude => {
if use_prelude && KNOWN_TOOLS.contains(&ident.name) {
let binding = (Res::ToolMod, ty::Visibility::Public,
DUMMY_SP, Mark::root()).to_name_binding(this.arenas);
Ok((binding, Flags::PRELUDE))
} else {
Err(Determinacy::Determined)
}
Scope::ToolPrelude => if KNOWN_TOOLS.contains(&ident.name) {
let binding = (Res::ToolMod, ty::Visibility::Public, DUMMY_SP, Mark::root())
.to_name_binding(this.arenas);
Ok((binding, Flags::PRELUDE))
} else {
Err(Determinacy::Determined)
}
Scope::StdLibPrelude => {
let mut result = Err(Determinacy::Determined);
if use_prelude {
if let Some(prelude) = this.prelude {
if let Ok(binding) = this.resolve_ident_in_module_unadjusted(
ModuleOrUniformRoot::Module(prelude),
ident,
ns,
false,
path_span,
) {
result = Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE));
}
if let Some(prelude) = this.prelude {
if let Ok(binding) = this.resolve_ident_in_module_unadjusted(
ModuleOrUniformRoot::Module(prelude),
ident,
ns,
false,
path_span,
) {
result = Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE));
}
}
result
}
Scope::BuiltinTypes => {
match this.primitive_type_table.primitive_types.get(&ident.name).cloned() {
Some(prim_ty) => {
let binding = (Res::PrimTy(prim_ty), ty::Visibility::Public,
DUMMY_SP, Mark::root()).to_name_binding(this.arenas);
Ok((binding, Flags::PRELUDE))
}
None => Err(Determinacy::Determined)
Scope::BuiltinTypes => match this.primitive_type_table.primitive_types
.get(&ident.name).cloned() {
Some(prim_ty) => {
let binding = (Res::PrimTy(prim_ty), ty::Visibility::Public,
DUMMY_SP, Mark::root()).to_name_binding(this.arenas);
Ok((binding, Flags::PRELUDE))
}
None => Err(Determinacy::Determined)
}
};
@ -712,7 +684,7 @@ impl<'a> Resolver<'a> {
// the last segment, so we are certainly working with a single-segment attribute here.)
assert!(ns == MacroNS);
let binding = (Res::NonMacroAttr(NonMacroAttrKind::Custom),
ty::Visibility::Public, ident.span, Mark::root())
ty::Visibility::Public, orig_ident.span, Mark::root())
.to_name_binding(self.arenas);
Ok(binding)
} else {