resolve: Move some common code into the scope visitor
This commit is contained in:
parent
329c05251a
commit
3845a08a55
3 changed files with 116 additions and 144 deletions
|
@ -562,19 +562,10 @@ impl<'a> Resolver<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
scope_set: ScopeSet,
|
scope_set: ScopeSet,
|
||||||
parent_scope: &ParentScope<'a>,
|
parent_scope: &ParentScope<'a>,
|
||||||
orig_ident: Ident,
|
ident: Ident,
|
||||||
filter_fn: &impl Fn(Res) -> bool,
|
filter_fn: &impl Fn(Res) -> bool,
|
||||||
) -> Option<TypoSuggestion> {
|
) -> 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 suggestions = Vec::new();
|
||||||
let mut use_prelude = !parent_scope.module.no_implicit_prelude;
|
|
||||||
|
|
||||||
self.visit_scopes(scope_set, parent_scope, ident, |this, scope, _| {
|
self.visit_scopes(scope_set, parent_scope, ident, |this, scope, _| {
|
||||||
match scope {
|
match scope {
|
||||||
Scope::DeriveHelpers => {
|
Scope::DeriveHelpers => {
|
||||||
|
@ -603,26 +594,22 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Scope::CrateRoot => {
|
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 root_module = this.resolve_crate_root(root_ident);
|
||||||
add_module_candidates(root_module, &mut suggestions, filter_fn);
|
add_module_candidates(root_module, &mut suggestions, filter_fn);
|
||||||
}
|
}
|
||||||
Scope::Module(module) => {
|
Scope::Module(module) => {
|
||||||
use_prelude = !module.no_implicit_prelude;
|
|
||||||
add_module_candidates(module, &mut suggestions, filter_fn);
|
add_module_candidates(module, &mut suggestions, filter_fn);
|
||||||
}
|
}
|
||||||
Scope::MacroUsePrelude => {
|
Scope::MacroUsePrelude => {
|
||||||
if use_prelude || rust_2015 {
|
suggestions.extend(this.macro_use_prelude.iter().filter_map(|(name, binding)| {
|
||||||
let macro_use_prelude = &this.macro_use_prelude;
|
let res = binding.res();
|
||||||
suggestions.extend(macro_use_prelude.iter().filter_map(|(name, binding)| {
|
if filter_fn(res) {
|
||||||
let res = binding.res();
|
Some(TypoSuggestion::from_res(*name, res))
|
||||||
if filter_fn(res) {
|
} else {
|
||||||
Some(TypoSuggestion::from_res(*name, res))
|
None
|
||||||
} else {
|
}
|
||||||
None
|
}));
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Scope::BuiltinMacros => {
|
Scope::BuiltinMacros => {
|
||||||
suggestions.extend(this.builtin_macros.iter().filter_map(|(name, binding)| {
|
suggestions.extend(this.builtin_macros.iter().filter_map(|(name, binding)| {
|
||||||
|
@ -643,41 +630,33 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Scope::LegacyPluginHelpers => {
|
Scope::LegacyPluginHelpers => {
|
||||||
if use_prelude || rust_2015 {
|
let res = Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper);
|
||||||
let res = Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper);
|
if filter_fn(res) {
|
||||||
if filter_fn(res) {
|
let plugin_attributes = this.session.plugin_attributes.borrow();
|
||||||
let plugin_attributes = this.session.plugin_attributes.borrow();
|
suggestions.extend(plugin_attributes.iter().map(|(name, _)| {
|
||||||
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| {
|
|
||||||
TypoSuggestion::from_res(*name, res)
|
TypoSuggestion::from_res(*name, res)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Scope::StdLibPrelude => {
|
Scope::ExternPrelude => {
|
||||||
if use_prelude {
|
suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
|
||||||
if let Some(prelude) = this.prelude {
|
let res = Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX));
|
||||||
add_module_candidates(prelude, &mut suggestions, filter_fn);
|
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 => {
|
Scope::BuiltinTypes => {
|
||||||
|
|
|
@ -2145,7 +2145,7 @@ impl<'a> Resolver<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
scope_set: ScopeSet,
|
scope_set: ScopeSet,
|
||||||
parent_scope: &ParentScope<'a>,
|
parent_scope: &ParentScope<'a>,
|
||||||
mut ident: Ident,
|
ident: Ident,
|
||||||
mut visitor: impl FnMut(&mut Self, Scope<'a>, Ident) -> Option<T>,
|
mut visitor: impl FnMut(&mut Self, Scope<'a>, Ident) -> Option<T>,
|
||||||
) -> Option<T> {
|
) -> Option<T> {
|
||||||
// General principles:
|
// General principles:
|
||||||
|
@ -2192,6 +2192,7 @@ impl<'a> Resolver<'a> {
|
||||||
// but introduced by legacy plugins using `register_attribute`. Priority is somewhere
|
// but introduced by legacy plugins using `register_attribute`. Priority is somewhere
|
||||||
// in prelude, not sure where exactly (creates ambiguities with any other prelude names).
|
// 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 {
|
let (ns, is_absolute_path) = match scope_set {
|
||||||
ScopeSet::Import(ns) => (ns, false),
|
ScopeSet::Import(ns) => (ns, false),
|
||||||
ScopeSet::AbsolutePath(ns) => (ns, true),
|
ScopeSet::AbsolutePath(ns) => (ns, true),
|
||||||
|
@ -2203,10 +2204,29 @@ impl<'a> Resolver<'a> {
|
||||||
TypeNS | ValueNS => Scope::Module(parent_scope.module),
|
TypeNS | ValueNS => Scope::Module(parent_scope.module),
|
||||||
MacroNS => Scope::DeriveHelpers,
|
MacroNS => Scope::DeriveHelpers,
|
||||||
};
|
};
|
||||||
|
let mut ident = ident.modern();
|
||||||
|
let mut use_prelude = !parent_scope.module.no_implicit_prelude;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let break_result @ Some(..) = visitor(self, scope, ident) {
|
let visit = match scope {
|
||||||
return break_result;
|
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 {
|
scope = match scope {
|
||||||
|
@ -2229,6 +2249,7 @@ impl<'a> Resolver<'a> {
|
||||||
ValueNS | MacroNS => break,
|
ValueNS | MacroNS => break,
|
||||||
}
|
}
|
||||||
Scope::Module(module) => {
|
Scope::Module(module) => {
|
||||||
|
use_prelude = !module.no_implicit_prelude;
|
||||||
match self.hygienic_lexical_parent(module, &mut ident.span) {
|
match self.hygienic_lexical_parent(module, &mut ident.span) {
|
||||||
Some(parent_module) => Scope::Module(parent_module),
|
Some(parent_module) => Scope::Module(parent_module),
|
||||||
None => {
|
None => {
|
||||||
|
|
|
@ -417,19 +417,17 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(force || !record_used); // `record_used` implies `force`
|
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.
|
// 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);
|
return Err(Determinacy::Determined);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rust_2015 = orig_ident.span.rust_2015();
|
let (ns, macro_kind, is_import) = match scope_set {
|
||||||
let (ns, macro_kind, is_import, is_absolute_path) = match scope_set {
|
ScopeSet::Import(ns) => (ns, None, true),
|
||||||
ScopeSet::Import(ns) => (ns, None, true, false),
|
ScopeSet::AbsolutePath(ns) => (ns, None, false),
|
||||||
ScopeSet::AbsolutePath(ns) => (ns, None, false, true),
|
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false),
|
||||||
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false, false),
|
ScopeSet::Module => (TypeNS, None, false),
|
||||||
ScopeSet::Module => (TypeNS, None, false, false),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is *the* result, resolution from the scope closest to the resolved identifier.
|
// 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
|
// So we have to save the innermost solution and continue searching in outer scopes
|
||||||
// to detect potential ambiguities.
|
// to detect potential ambiguities.
|
||||||
let mut innermost_result: Option<(&NameBinding<'_>, Flags)> = None;
|
let mut innermost_result: Option<(&NameBinding<'_>, Flags)> = None;
|
||||||
let mut use_prelude = !parent_scope.module.no_implicit_prelude;
|
|
||||||
let mut determinacy = Determinacy::Determined;
|
let mut determinacy = Determinacy::Determined;
|
||||||
|
|
||||||
// Go through all the scopes and try to resolve the name.
|
// 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 {
|
let result = match scope {
|
||||||
Scope::DeriveHelpers => {
|
Scope::DeriveHelpers => {
|
||||||
let mut result = Err(Determinacy::Determined);
|
let mut result = Err(Determinacy::Determined);
|
||||||
|
@ -478,11 +476,11 @@ impl<'a> Resolver<'a> {
|
||||||
_ => Err(Determinacy::Determined),
|
_ => Err(Determinacy::Determined),
|
||||||
}
|
}
|
||||||
Scope::CrateRoot => {
|
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 root_module = this.resolve_crate_root(root_ident);
|
||||||
let binding = this.resolve_ident_in_module_ext(
|
let binding = this.resolve_ident_in_module_ext(
|
||||||
ModuleOrUniformRoot::Module(root_module),
|
ModuleOrUniformRoot::Module(root_module),
|
||||||
orig_ident,
|
ident,
|
||||||
ns,
|
ns,
|
||||||
None,
|
None,
|
||||||
record_used,
|
record_used,
|
||||||
|
@ -498,7 +496,6 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Scope::Module(module) => {
|
Scope::Module(module) => {
|
||||||
use_prelude = !module.no_implicit_prelude;
|
|
||||||
let orig_current_module = mem::replace(&mut this.current_module, module);
|
let orig_current_module = mem::replace(&mut this.current_module, module);
|
||||||
let binding = this.resolve_ident_in_module_unadjusted_ext(
|
let binding = this.resolve_ident_in_module_unadjusted_ext(
|
||||||
ModuleOrUniformRoot::Module(module),
|
ModuleOrUniformRoot::Module(module),
|
||||||
|
@ -528,94 +525,69 @@ impl<'a> Resolver<'a> {
|
||||||
Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
|
Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Scope::MacroUsePrelude => {
|
Scope::MacroUsePrelude => match this.macro_use_prelude.get(&ident.name).cloned() {
|
||||||
if use_prelude || rust_2015 {
|
Some(binding) => Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)),
|
||||||
match this.macro_use_prelude.get(&ident.name).cloned() {
|
None => Err(Determinacy::determined(
|
||||||
Some(binding) =>
|
this.graph_root.unresolved_invocations.borrow().is_empty()
|
||||||
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::BuiltinMacros => {
|
Scope::BuiltinMacros => match this.builtin_macros.get(&ident.name).cloned() {
|
||||||
match this.builtin_macros.get(&ident.name).cloned() {
|
Some(binding) => Ok((binding, Flags::PRELUDE)),
|
||||||
Some(binding) => Ok((binding, Flags::PRELUDE)),
|
None => Err(Determinacy::Determined),
|
||||||
None => Err(Determinacy::Determined),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Scope::BuiltinAttrs => {
|
Scope::BuiltinAttrs => if is_builtin_attr_name(ident.name) {
|
||||||
if is_builtin_attr_name(ident.name) {
|
let binding = (Res::NonMacroAttr(NonMacroAttrKind::Builtin),
|
||||||
let binding = (Res::NonMacroAttr(NonMacroAttrKind::Builtin),
|
ty::Visibility::Public, DUMMY_SP, Mark::root())
|
||||||
ty::Visibility::Public, DUMMY_SP, Mark::root())
|
.to_name_binding(this.arenas);
|
||||||
.to_name_binding(this.arenas);
|
Ok((binding, Flags::PRELUDE))
|
||||||
Ok((binding, Flags::PRELUDE))
|
} else {
|
||||||
} else {
|
Err(Determinacy::Determined)
|
||||||
Err(Determinacy::Determined)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Scope::LegacyPluginHelpers => {
|
Scope::LegacyPluginHelpers => if this.session.plugin_attributes.borrow().iter()
|
||||||
if (use_prelude || rust_2015) &&
|
|
||||||
this.session.plugin_attributes.borrow().iter()
|
|
||||||
.any(|(name, _)| ident.name == *name) {
|
.any(|(name, _)| ident.name == *name) {
|
||||||
let binding = (Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),
|
let binding = (Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),
|
||||||
ty::Visibility::Public, DUMMY_SP, Mark::root())
|
ty::Visibility::Public, DUMMY_SP, Mark::root())
|
||||||
.to_name_binding(this.arenas);
|
.to_name_binding(this.arenas);
|
||||||
Ok((binding, Flags::PRELUDE))
|
Ok((binding, Flags::PRELUDE))
|
||||||
} else {
|
} else {
|
||||||
Err(Determinacy::Determined)
|
Err(Determinacy::Determined)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Scope::ExternPrelude => {
|
Scope::ExternPrelude => match this.extern_prelude_get(ident, !record_used) {
|
||||||
if use_prelude || is_absolute_path {
|
Some(binding) => Ok((binding, Flags::PRELUDE)),
|
||||||
match this.extern_prelude_get(ident, !record_used) {
|
None => Err(Determinacy::determined(
|
||||||
Some(binding) => Ok((binding, Flags::PRELUDE)),
|
this.graph_root.unresolved_invocations.borrow().is_empty()
|
||||||
None => Err(Determinacy::determined(
|
)),
|
||||||
this.graph_root.unresolved_invocations.borrow().is_empty()
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(Determinacy::Determined)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Scope::ToolPrelude => {
|
Scope::ToolPrelude => if KNOWN_TOOLS.contains(&ident.name) {
|
||||||
if use_prelude && KNOWN_TOOLS.contains(&ident.name) {
|
let binding = (Res::ToolMod, ty::Visibility::Public, DUMMY_SP, Mark::root())
|
||||||
let binding = (Res::ToolMod, ty::Visibility::Public,
|
.to_name_binding(this.arenas);
|
||||||
DUMMY_SP, Mark::root()).to_name_binding(this.arenas);
|
Ok((binding, Flags::PRELUDE))
|
||||||
Ok((binding, Flags::PRELUDE))
|
} else {
|
||||||
} else {
|
Err(Determinacy::Determined)
|
||||||
Err(Determinacy::Determined)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Scope::StdLibPrelude => {
|
Scope::StdLibPrelude => {
|
||||||
let mut result = Err(Determinacy::Determined);
|
let mut result = Err(Determinacy::Determined);
|
||||||
if use_prelude {
|
if let Some(prelude) = this.prelude {
|
||||||
if let Some(prelude) = this.prelude {
|
if let Ok(binding) = this.resolve_ident_in_module_unadjusted(
|
||||||
if let Ok(binding) = this.resolve_ident_in_module_unadjusted(
|
ModuleOrUniformRoot::Module(prelude),
|
||||||
ModuleOrUniformRoot::Module(prelude),
|
ident,
|
||||||
ident,
|
ns,
|
||||||
ns,
|
false,
|
||||||
false,
|
path_span,
|
||||||
path_span,
|
) {
|
||||||
) {
|
result = Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE));
|
||||||
result = Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
Scope::BuiltinTypes => {
|
Scope::BuiltinTypes => match this.primitive_type_table.primitive_types
|
||||||
match this.primitive_type_table.primitive_types.get(&ident.name).cloned() {
|
.get(&ident.name).cloned() {
|
||||||
Some(prim_ty) => {
|
Some(prim_ty) => {
|
||||||
let binding = (Res::PrimTy(prim_ty), ty::Visibility::Public,
|
let binding = (Res::PrimTy(prim_ty), ty::Visibility::Public,
|
||||||
DUMMY_SP, Mark::root()).to_name_binding(this.arenas);
|
DUMMY_SP, Mark::root()).to_name_binding(this.arenas);
|
||||||
Ok((binding, Flags::PRELUDE))
|
Ok((binding, Flags::PRELUDE))
|
||||||
}
|
|
||||||
None => Err(Determinacy::Determined)
|
|
||||||
}
|
}
|
||||||
|
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.)
|
// the last segment, so we are certainly working with a single-segment attribute here.)
|
||||||
assert!(ns == MacroNS);
|
assert!(ns == MacroNS);
|
||||||
let binding = (Res::NonMacroAttr(NonMacroAttrKind::Custom),
|
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);
|
.to_name_binding(self.arenas);
|
||||||
Ok(binding)
|
Ok(binding)
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue