1pub mod assoc;
51pub mod attr_resolution;
52mod collector;
53pub mod diagnostics;
54mod mod_resolution;
55mod path_resolution;
56pub mod proc_macro;
57
58#[cfg(test)]
59mod tests;
60
61use std::ops::Deref;
62
63use base_db::Crate;
64use hir_expand::{
65 EditionedFileId, ErasedAstId, HirFileId, InFile, MacroCallId, mod_path::ModPath, name::Name,
66 proc_macro::ProcMacroKind,
67};
68use intern::Symbol;
69use itertools::Itertools;
70use la_arena::Arena;
71use rustc_hash::{FxHashMap, FxHashSet};
72use span::{Edition, FileAstId, FileId, ROOT_ERASED_FILE_AST_ID};
73use stdx::format_to;
74use syntax::{AstNode, SmolStr, SyntaxNode, ToSmolStr, ast};
75use triomphe::Arc;
76use tt::TextRange;
77
78use crate::{
79 AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, FxIndexMap,
80 LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
81 db::DefDatabase,
82 item_scope::{BuiltinShadowMode, ItemScope},
83 item_tree::TreeId,
84 nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
85 per_ns::PerNs,
86 visibility::{Visibility, VisibilityExplicitness},
87};
88
89pub use self::path_resolution::ResolvePathResultPrefixInfo;
90
91const PREDEFINED_TOOLS: &[SmolStr] = &[
92 SmolStr::new_static("clippy"),
93 SmolStr::new_static("rustfmt"),
94 SmolStr::new_static("diagnostic"),
95 SmolStr::new_static("miri"),
96 SmolStr::new_static("rust_analyzer"),
97];
98
99#[derive(Debug, PartialEq, Eq, Default)]
108pub struct LocalDefMap {
109 extern_prelude: FxIndexMap<Name, (CrateRootModuleId, Option<ExternCrateId>)>,
113}
114
115impl std::hash::Hash for LocalDefMap {
116 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
117 let LocalDefMap { extern_prelude } = self;
118 extern_prelude.len().hash(state);
119 for (name, (crate_root, extern_crate)) in extern_prelude {
120 name.hash(state);
121 crate_root.hash(state);
122 extern_crate.hash(state);
123 }
124 }
125}
126
127impl LocalDefMap {
128 pub(crate) const EMPTY: &Self =
129 &Self { extern_prelude: FxIndexMap::with_hasher(rustc_hash::FxBuildHasher) };
130
131 fn shrink_to_fit(&mut self) {
132 let Self { extern_prelude } = self;
133 extern_prelude.shrink_to_fit();
134 }
135
136 pub(crate) fn extern_prelude(
137 &self,
138 ) -> impl DoubleEndedIterator<Item = (&Name, (CrateRootModuleId, Option<ExternCrateId>))> + '_
139 {
140 self.extern_prelude.iter().map(|(name, &def)| (name, def))
141 }
142}
143
144#[derive(Debug, PartialEq, Eq)]
154pub struct DefMap {
155 krate: Crate,
157 block: Option<BlockInfo>,
160 pub modules: Arena<ModuleData>,
162 prelude: Option<(ModuleId, Option<UseId>)>,
169 macro_use_prelude: FxHashMap<Name, (MacroId, Option<ExternCrateId>)>,
173
174 derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>,
178 pub macro_def_to_macro_id: FxHashMap<ErasedAstId, MacroId>,
180
181 diagnostics: Vec<DefDiagnostic>,
183
184 data: Arc<DefMapCrateData>,
186}
187
188#[derive(Clone, Debug, PartialEq, Eq)]
190struct DefMapCrateData {
191 exported_derives: FxHashMap<MacroId, Box<[Name]>>,
193 fn_proc_macro_mapping: FxHashMap<FunctionId, ProcMacroId>,
194
195 registered_attrs: Vec<Symbol>,
197 registered_tools: Vec<Symbol>,
199 unstable_features: FxHashSet<Symbol>,
201 rustc_coherence_is_core: bool,
203 no_core: bool,
204 no_std: bool,
205
206 edition: Edition,
207 recursion_limit: Option<u32>,
208}
209
210impl DefMapCrateData {
211 fn new(edition: Edition) -> Self {
212 Self {
213 exported_derives: FxHashMap::default(),
214 fn_proc_macro_mapping: FxHashMap::default(),
215 registered_attrs: Vec::new(),
216 registered_tools: PREDEFINED_TOOLS.iter().map(|it| Symbol::intern(it)).collect(),
217 unstable_features: FxHashSet::default(),
218 rustc_coherence_is_core: false,
219 no_core: false,
220 no_std: false,
221 edition,
222 recursion_limit: None,
223 }
224 }
225
226 fn shrink_to_fit(&mut self) {
227 let Self {
228 exported_derives,
229 fn_proc_macro_mapping,
230 registered_attrs,
231 registered_tools,
232 unstable_features,
233 rustc_coherence_is_core: _,
234 no_core: _,
235 no_std: _,
236 edition: _,
237 recursion_limit: _,
238 } = self;
239 exported_derives.shrink_to_fit();
240 fn_proc_macro_mapping.shrink_to_fit();
241 registered_attrs.shrink_to_fit();
242 registered_tools.shrink_to_fit();
243 unstable_features.shrink_to_fit();
244 }
245}
246
247#[derive(Debug, PartialEq, Eq, Clone, Copy)]
249struct BlockInfo {
250 block: BlockId,
252 parent: BlockRelativeModuleId,
254}
255
256#[derive(Debug, PartialEq, Eq, Clone, Copy)]
257struct BlockRelativeModuleId {
258 block: Option<BlockId>,
259 local_id: LocalModuleId,
260}
261
262impl BlockRelativeModuleId {
263 fn def_map(self, db: &dyn DefDatabase, krate: Crate) -> &DefMap {
264 self.into_module(krate).def_map(db)
265 }
266
267 fn into_module(self, krate: Crate) -> ModuleId {
268 ModuleId { krate, block: self.block, local_id: self.local_id }
269 }
270
271 fn is_block_module(self) -> bool {
272 self.block.is_some() && self.local_id == DefMap::ROOT
273 }
274}
275
276impl std::ops::Index<LocalModuleId> for DefMap {
277 type Output = ModuleData;
278 fn index(&self, id: LocalModuleId) -> &ModuleData {
279 &self.modules[id]
280 }
281}
282
283#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
284pub enum ModuleOrigin {
285 CrateRoot {
286 definition: EditionedFileId,
287 },
288 File {
290 is_mod_rs: bool,
291 declaration: FileAstId<ast::Module>,
292 declaration_tree_id: TreeId,
293 definition: EditionedFileId,
294 },
295 Inline {
296 definition_tree_id: TreeId,
297 definition: FileAstId<ast::Module>,
298 },
299 BlockExpr {
301 id: BlockId,
302 block: AstId<ast::BlockExpr>,
303 },
304}
305
306impl ModuleOrigin {
307 pub fn declaration(&self) -> Option<AstId<ast::Module>> {
308 match self {
309 &ModuleOrigin::File { declaration, declaration_tree_id, .. } => {
310 Some(AstId::new(declaration_tree_id.file_id(), declaration))
311 }
312 &ModuleOrigin::Inline { definition, definition_tree_id } => {
313 Some(AstId::new(definition_tree_id.file_id(), definition))
314 }
315 ModuleOrigin::CrateRoot { .. } | ModuleOrigin::BlockExpr { .. } => None,
316 }
317 }
318
319 pub fn file_id(&self) -> Option<EditionedFileId> {
320 match self {
321 ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
322 Some(*definition)
323 }
324 _ => None,
325 }
326 }
327
328 pub fn is_inline(&self) -> bool {
329 match self {
330 ModuleOrigin::Inline { .. } | ModuleOrigin::BlockExpr { .. } => true,
331 ModuleOrigin::CrateRoot { .. } | ModuleOrigin::File { .. } => false,
332 }
333 }
334
335 pub fn definition_source(&self, db: &dyn DefDatabase) -> InFile<ModuleSource> {
338 match self {
339 &ModuleOrigin::File { definition: editioned_file_id, .. }
340 | &ModuleOrigin::CrateRoot { definition: editioned_file_id } => {
341 let sf = db.parse(editioned_file_id).tree();
342 InFile::new(editioned_file_id.into(), ModuleSource::SourceFile(sf))
343 }
344 &ModuleOrigin::Inline { definition, definition_tree_id } => InFile::new(
345 definition_tree_id.file_id(),
346 ModuleSource::Module(
347 AstId::new(definition_tree_id.file_id(), definition).to_node(db),
348 ),
349 ),
350 ModuleOrigin::BlockExpr { block, .. } => {
351 InFile::new(block.file_id, ModuleSource::BlockExpr(block.to_node(db)))
352 }
353 }
354 }
355}
356
357#[derive(Debug, PartialEq, Eq)]
358pub struct ModuleData {
359 pub origin: ModuleOrigin,
361 pub visibility: Visibility,
363 pub parent: Option<LocalModuleId>,
367 pub children: FxIndexMap<Name, LocalModuleId>,
368 pub scope: ItemScope,
369}
370
371#[inline]
372pub fn crate_def_map(db: &dyn DefDatabase, crate_id: Crate) -> &DefMap {
373 crate_local_def_map(db, crate_id).def_map(db)
374}
375
376#[salsa_macros::tracked]
377pub(crate) struct DefMapPair<'db> {
378 #[tracked]
379 #[returns(ref)]
380 pub(crate) def_map: DefMap,
381 #[returns(ref)]
382 pub(crate) local: LocalDefMap,
383}
384
385#[salsa_macros::tracked(returns(ref))]
386pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefMapPair<'_> {
387 let krate = crate_id.data(db);
388 let _p = tracing::info_span!(
389 "crate_def_map_query",
390 name=?crate_id
391 .extra_data(db)
392 .display_name
393 .as_ref()
394 .map(|it| it.crate_name().to_smolstr())
395 .unwrap_or_default()
396 )
397 .entered();
398
399 let module_data = ModuleData::new(
400 ModuleOrigin::CrateRoot { definition: krate.root_file_id(db) },
401 Visibility::Public,
402 );
403
404 let def_map =
405 DefMap::empty(crate_id, Arc::new(DefMapCrateData::new(krate.edition)), module_data, None);
406 let (def_map, local_def_map) = collector::collect_defs(
407 db,
408 def_map,
409 TreeId::new(krate.root_file_id(db).into(), None),
410 None,
411 );
412
413 DefMapPair::new(db, def_map, local_def_map)
414}
415
416#[salsa_macros::tracked(returns(ref))]
417pub fn block_def_map(db: &dyn DefDatabase, block_id: BlockId) -> DefMap {
418 let BlockLoc { ast_id, module } = block_id.lookup(db);
419
420 let visibility = Visibility::Module(
421 ModuleId { krate: module.krate, local_id: DefMap::ROOT, block: module.block },
422 VisibilityExplicitness::Implicit,
423 );
424 let module_data =
425 ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility);
426
427 let local_def_map = crate_local_def_map(db, module.krate);
428 let def_map = DefMap::empty(
429 module.krate,
430 local_def_map.def_map(db).data.clone(),
431 module_data,
432 Some(BlockInfo {
433 block: block_id,
434 parent: BlockRelativeModuleId { block: module.block, local_id: module.local_id },
435 }),
436 );
437
438 let (def_map, _) = collector::collect_defs(
439 db,
440 def_map,
441 TreeId::new(ast_id.file_id, Some(block_id)),
442 Some(local_def_map.local(db)),
443 );
444 def_map
445}
446
447impl DefMap {
448 pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0));
450
451 pub fn edition(&self) -> Edition {
452 self.data.edition
453 }
454
455 fn empty(
456 krate: Crate,
457 crate_data: Arc<DefMapCrateData>,
458 module_data: ModuleData,
459 block: Option<BlockInfo>,
460 ) -> DefMap {
461 let mut modules: Arena<ModuleData> = Arena::default();
462 let root = modules.alloc(module_data);
463 assert_eq!(root, Self::ROOT);
464
465 DefMap {
466 block,
467 modules,
468 krate,
469 prelude: None,
470 macro_use_prelude: FxHashMap::default(),
471 derive_helpers_in_scope: FxHashMap::default(),
472 diagnostics: Vec::new(),
473 data: crate_data,
474 macro_def_to_macro_id: FxHashMap::default(),
475 }
476 }
477 fn shrink_to_fit(&mut self) {
478 let Self {
480 macro_use_prelude,
481 diagnostics,
482 modules,
483 derive_helpers_in_scope,
484 block: _,
485 krate: _,
486 prelude: _,
487 data: _,
488 macro_def_to_macro_id,
489 } = self;
490
491 macro_def_to_macro_id.shrink_to_fit();
492 macro_use_prelude.shrink_to_fit();
493 diagnostics.shrink_to_fit();
494 modules.shrink_to_fit();
495 derive_helpers_in_scope.shrink_to_fit();
496 for (_, module) in modules.iter_mut() {
497 module.children.shrink_to_fit();
498 module.scope.shrink_to_fit();
499 }
500 }
501}
502
503impl DefMap {
504 pub fn modules_for_file<'a>(
505 &'a self,
506 db: &'a dyn DefDatabase,
507 file_id: FileId,
508 ) -> impl Iterator<Item = LocalModuleId> + 'a {
509 self.modules
510 .iter()
511 .filter(move |(_id, data)| {
512 data.origin.file_id().map(|file_id| file_id.file_id(db)) == Some(file_id)
513 })
514 .map(|(id, _data)| id)
515 }
516
517 pub fn modules(&self) -> impl Iterator<Item = (LocalModuleId, &ModuleData)> + '_ {
518 self.modules.iter()
519 }
520
521 pub fn derive_helpers_in_scope(
522 &self,
523 id: AstId<ast::Adt>,
524 ) -> Option<&[(Name, MacroId, MacroCallId)]> {
525 self.derive_helpers_in_scope.get(&id.map(|it| it.upcast())).map(Deref::deref)
526 }
527
528 pub fn registered_tools(&self) -> &[Symbol] {
529 &self.data.registered_tools
530 }
531
532 pub fn registered_attrs(&self) -> &[Symbol] {
533 &self.data.registered_attrs
534 }
535
536 pub fn is_unstable_feature_enabled(&self, feature: &Symbol) -> bool {
537 self.data.unstable_features.contains(feature)
538 }
539
540 pub fn is_rustc_coherence_is_core(&self) -> bool {
541 self.data.rustc_coherence_is_core
542 }
543
544 pub fn is_no_std(&self) -> bool {
545 self.data.no_std || self.data.no_core
546 }
547
548 pub fn is_no_core(&self) -> bool {
549 self.data.no_core
550 }
551
552 pub fn fn_as_proc_macro(&self, id: FunctionId) -> Option<ProcMacroId> {
553 self.data.fn_proc_macro_mapping.get(&id).copied()
554 }
555
556 pub fn krate(&self) -> Crate {
557 self.krate
558 }
559
560 pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId {
561 let block = self.block.map(|b| b.block);
562 ModuleId { krate: self.krate, local_id, block }
563 }
564
565 pub fn crate_root(&self) -> CrateRootModuleId {
566 CrateRootModuleId { krate: self.krate }
567 }
568
569 pub fn root_module_id(&self) -> ModuleId {
572 self.module_id(Self::ROOT)
573 }
574
575 pub fn parent(&self) -> Option<ModuleId> {
578 let BlockRelativeModuleId { block, local_id } = self.block?.parent;
579 Some(ModuleId { krate: self.krate, block, local_id })
580 }
581
582 pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> {
585 match self[local_mod].parent {
586 Some(parent) => Some(self.module_id(parent)),
587 None => {
588 self.block.map(
589 |BlockInfo { parent: BlockRelativeModuleId { block, local_id }, .. }| {
590 ModuleId { krate: self.krate, block, local_id }
591 },
592 )
593 }
594 }
595 }
596
597 pub fn diagnostics(&self) -> &[DefDiagnostic] {
599 self.diagnostics.as_slice()
600 }
601
602 pub fn recursion_limit(&self) -> u32 {
603 self.data.recursion_limit.unwrap_or(128)
605 }
606
607 pub fn dump(&self, db: &dyn DefDatabase) -> String {
610 let mut buf = String::new();
611 let mut arc;
612 let mut current_map = self;
613 while let Some(block) = current_map.block {
614 go(&mut buf, db, current_map, "block scope", Self::ROOT);
615 buf.push('\n');
616 arc = block.parent.def_map(db, self.krate);
617 current_map = arc;
618 }
619 go(&mut buf, db, current_map, "crate", Self::ROOT);
620 return buf;
621
622 fn go(
623 buf: &mut String,
624 db: &dyn DefDatabase,
625 map: &DefMap,
626 path: &str,
627 module: LocalModuleId,
628 ) {
629 format_to!(buf, "{}\n", path);
630
631 map.modules[module].scope.dump(db, buf);
632
633 for (name, child) in
634 map.modules[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0))
635 {
636 let path = format!("{path}::{}", name.display(db, Edition::LATEST));
637 buf.push('\n');
638 go(buf, db, map, &path, *child);
639 }
640 }
641 }
642
643 pub fn dump_block_scopes(&self, db: &dyn DefDatabase) -> String {
644 let mut buf = String::new();
645 let mut arc;
646 let mut current_map = self;
647 while let Some(block) = current_map.block {
648 format_to!(buf, "{:?} in {:?}\n", block.block, block.parent);
649 arc = block.parent.def_map(db, self.krate);
650 current_map = arc;
651 }
652
653 format_to!(buf, "crate scope\n");
654 buf
655 }
656}
657
658impl DefMap {
659 pub(crate) fn block_id(&self) -> Option<BlockId> {
660 self.block.map(|block| block.block)
661 }
662
663 pub(crate) fn prelude(&self) -> Option<(ModuleId, Option<UseId>)> {
664 self.prelude
665 }
666
667 pub(crate) fn macro_use_prelude(&self) -> &FxHashMap<Name, (MacroId, Option<ExternCrateId>)> {
668 &self.macro_use_prelude
669 }
670
671 pub(crate) fn resolve_path(
672 &self,
673 local_def_map: &LocalDefMap,
674 db: &dyn DefDatabase,
675 original_module: LocalModuleId,
676 path: &ModPath,
677 shadow: BuiltinShadowMode,
678 expected_macro_subns: Option<MacroSubNs>,
679 ) -> (PerNs, Option<usize>) {
680 let res = self.resolve_path_fp_with_macro(
681 local_def_map,
682 db,
683 ResolveMode::Other,
684 original_module,
685 path,
686 shadow,
687 expected_macro_subns,
688 );
689 (res.resolved_def, res.segment_index)
690 }
691
692 pub(crate) fn resolve_path_locally(
695 &self,
696 local_def_map: &LocalDefMap,
697 db: &dyn DefDatabase,
698 original_module: LocalModuleId,
699 path: &ModPath,
700 shadow: BuiltinShadowMode,
701 ) -> (PerNs, Option<usize>, ResolvePathResultPrefixInfo) {
702 let res = self.resolve_path_fp_with_macro_single(
703 local_def_map,
704 db,
705 ResolveMode::Other,
706 original_module,
707 path,
708 shadow,
709 None, );
711 (res.resolved_def, res.segment_index, res.prefix_info)
712 }
713
714 pub(crate) fn with_ancestor_maps<T>(
719 &self,
720 db: &dyn DefDatabase,
721 local_mod: LocalModuleId,
722 f: &mut dyn FnMut(&DefMap, LocalModuleId) -> Option<T>,
723 ) -> Option<T> {
724 if let Some(it) = f(self, local_mod) {
725 return Some(it);
726 }
727 let mut block = self.block;
728 while let Some(block_info) = block {
729 let parent = block_info.parent.def_map(db, self.krate);
730 if let Some(it) = f(parent, block_info.parent.local_id) {
731 return Some(it);
732 }
733 block = parent.block;
734 }
735
736 None
737 }
738}
739
740impl ModuleData {
741 pub(crate) fn new(origin: ModuleOrigin, visibility: Visibility) -> Self {
742 ModuleData {
743 origin,
744 visibility,
745 parent: None,
746 children: Default::default(),
747 scope: ItemScope::default(),
748 }
749 }
750
751 pub fn definition_source(&self, db: &dyn DefDatabase) -> InFile<ModuleSource> {
753 self.origin.definition_source(db)
754 }
755
756 pub fn definition_source_file_id(&self) -> HirFileId {
758 match self.origin {
759 ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
760 definition.into()
761 }
762 ModuleOrigin::Inline { definition_tree_id, .. } => definition_tree_id.file_id(),
763 ModuleOrigin::BlockExpr { block, .. } => block.file_id,
764 }
765 }
766
767 pub fn definition_source_range(&self, db: &dyn DefDatabase) -> InFile<TextRange> {
768 match &self.origin {
769 &ModuleOrigin::File { definition, .. } | &ModuleOrigin::CrateRoot { definition } => {
770 InFile::new(
771 definition.into(),
772 ErasedAstId::new(definition.into(), ROOT_ERASED_FILE_AST_ID).to_range(db),
773 )
774 }
775 &ModuleOrigin::Inline { definition, definition_tree_id } => InFile::new(
776 definition_tree_id.file_id(),
777 AstId::new(definition_tree_id.file_id(), definition).to_range(db),
778 ),
779 ModuleOrigin::BlockExpr { block, .. } => InFile::new(block.file_id, block.to_range(db)),
780 }
781 }
782
783 pub fn declaration_source(&self, db: &dyn DefDatabase) -> Option<InFile<ast::Module>> {
786 let decl = self.origin.declaration()?;
787 let value = decl.to_node(db);
788 Some(InFile { file_id: decl.file_id, value })
789 }
790
791 pub fn declaration_source_range(&self, db: &dyn DefDatabase) -> Option<InFile<TextRange>> {
794 let decl = self.origin.declaration()?;
795 Some(InFile { file_id: decl.file_id, value: decl.to_range(db) })
796 }
797}
798
799#[derive(Debug, Clone, PartialEq, Eq)]
800pub enum ModuleSource {
801 SourceFile(ast::SourceFile),
802 Module(ast::Module),
803 BlockExpr(ast::BlockExpr),
804}
805
806impl ModuleSource {
807 pub fn node(&self) -> SyntaxNode {
808 match self {
809 ModuleSource::SourceFile(it) => it.syntax().clone(),
810 ModuleSource::Module(it) => it.syntax().clone(),
811 ModuleSource::BlockExpr(it) => it.syntax().clone(),
812 }
813 }
814}
815
816#[derive(Clone, Copy, PartialEq, Eq)]
818pub enum MacroSubNs {
819 Bang,
821 Attr,
823}
824
825impl MacroSubNs {
826 fn from_id(db: &dyn DefDatabase, macro_id: MacroId) -> Self {
827 let expander = match macro_id {
828 MacroId::Macro2Id(it) => it.lookup(db).expander,
829 MacroId::MacroRulesId(it) => it.lookup(db).expander,
830 MacroId::ProcMacroId(it) => {
831 return match it.lookup(db).kind {
832 ProcMacroKind::CustomDerive | ProcMacroKind::Attr => Self::Attr,
833 ProcMacroKind::Bang => Self::Bang,
834 };
835 }
836 };
837
838 match expander {
840 MacroExpander::Declarative
841 | MacroExpander::BuiltIn(_)
842 | MacroExpander::BuiltInEager(_) => Self::Bang,
843 MacroExpander::BuiltInAttr(_) | MacroExpander::BuiltInDerive(_) => Self::Attr,
844 }
845 }
846}
847
848fn sub_namespace_match(candidate: Option<MacroSubNs>, expected: Option<MacroSubNs>) -> bool {
855 match (candidate, expected) {
856 (Some(candidate), Some(expected)) => candidate == expected,
857 _ => true,
858 }
859}