diff options
author | Paul Daniel Faria <[email protected]> | 2020-06-25 17:42:12 +0100 |
---|---|---|
committer | Paul Daniel Faria <[email protected]> | 2020-06-25 17:42:12 +0100 |
commit | de9e964e4ac21897bd48adbe37f379d74422919f (patch) | |
tree | 75749d75444e360b89b3161623934e2f255ff643 /crates/ra_hir_def | |
parent | 0b657ddbfe9754afce9811c70a4e61e4ea9efeaf (diff) |
Track import type outside of , use enum rather than bool to improve readability
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r-- | crates/ra_hir_def/src/body/lower.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir_def/src/item_scope.rs | 51 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/collector.rs | 36 | ||||
-rw-r--r-- | crates/ra_hir_def/src/per_ns.rs | 20 |
4 files changed, 73 insertions, 40 deletions
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 3ced648e5..d749c828d 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -26,7 +26,7 @@ use crate::{ | |||
26 | dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, | 26 | dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, |
27 | LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, | 27 | LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, |
28 | }, | 28 | }, |
29 | item_scope::BuiltinShadowMode, | 29 | item_scope::{BuiltinShadowMode, ImportType}, |
30 | item_tree::{FileItemTreeId, ItemTree, ItemTreeNode}, | 30 | item_tree::{FileItemTreeId, ItemTree, ItemTreeNode}, |
31 | path::{GenericArgs, Path}, | 31 | path::{GenericArgs, Path}, |
32 | type_ref::{Mutability, Rawness, TypeRef}, | 32 | type_ref::{Mutability, Rawness, TypeRef}, |
@@ -81,6 +81,7 @@ pub(super) fn lower( | |||
81 | map | 81 | map |
82 | }, | 82 | }, |
83 | expander, | 83 | expander, |
84 | import_types: FxHashMap::default(), | ||
84 | } | 85 | } |
85 | .collect(params, body) | 86 | .collect(params, body) |
86 | } | 87 | } |
@@ -93,6 +94,7 @@ struct ExprCollector<'a> { | |||
93 | source_map: BodySourceMap, | 94 | source_map: BodySourceMap, |
94 | 95 | ||
95 | item_trees: FxHashMap<HirFileId, Arc<ItemTree>>, | 96 | item_trees: FxHashMap<HirFileId, Arc<ItemTree>>, |
97 | import_types: FxHashMap<Name, ImportType>, | ||
96 | } | 98 | } |
97 | 99 | ||
98 | impl ExprCollector<'_> { | 100 | impl ExprCollector<'_> { |
@@ -711,8 +713,10 @@ impl ExprCollector<'_> { | |||
711 | _ => true, | 713 | _ => true, |
712 | }; | 714 | }; |
713 | self.body.item_scope.push_res( | 715 | self.body.item_scope.push_res( |
716 | &mut self.import_types, | ||
714 | name.as_name(), | 717 | name.as_name(), |
715 | crate::per_ns::PerNs::from_def(def, vis, has_constructor), | 718 | crate::per_ns::PerNs::from_def(def, vis, has_constructor), |
719 | ImportType::Named, | ||
716 | ); | 720 | ); |
717 | } | 721 | } |
718 | } | 722 | } |
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs index 0184b6af9..511c08a8d 100644 --- a/crates/ra_hir_def/src/item_scope.rs +++ b/crates/ra_hir_def/src/item_scope.rs | |||
@@ -12,6 +12,28 @@ use crate::{ | |||
12 | Lookup, MacroDefId, ModuleDefId, TraitId, | 12 | Lookup, MacroDefId, ModuleDefId, TraitId, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | #[derive(Copy, Clone)] | ||
16 | pub(crate) enum ImportType { | ||
17 | Glob, | ||
18 | Named, | ||
19 | } | ||
20 | |||
21 | impl ImportType { | ||
22 | fn is_glob(&self) -> bool { | ||
23 | match self { | ||
24 | ImportType::Glob => true, | ||
25 | ImportType::Named => false, | ||
26 | } | ||
27 | } | ||
28 | |||
29 | fn is_named(&self) -> bool { | ||
30 | match self { | ||
31 | ImportType::Glob => false, | ||
32 | ImportType::Named => true, | ||
33 | } | ||
34 | } | ||
35 | } | ||
36 | |||
15 | #[derive(Debug, Default, PartialEq, Eq)] | 37 | #[derive(Debug, Default, PartialEq, Eq)] |
16 | pub struct ItemScope { | 38 | pub struct ItemScope { |
17 | visible: FxHashMap<Name, PerNs>, | 39 | visible: FxHashMap<Name, PerNs>, |
@@ -123,23 +145,30 @@ impl ItemScope { | |||
123 | self.legacy_macros.insert(name, mac); | 145 | self.legacy_macros.insert(name, mac); |
124 | } | 146 | } |
125 | 147 | ||
126 | pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool { | 148 | pub(crate) fn push_res( |
149 | &mut self, | ||
150 | existing_import_map: &mut FxHashMap<Name, ImportType>, | ||
151 | name: Name, | ||
152 | def: PerNs, | ||
153 | def_import_type: ImportType, | ||
154 | ) -> bool { | ||
127 | let mut changed = false; | 155 | let mut changed = false; |
128 | let existing = self.visible.entry(name).or_default(); | 156 | let existing = self.visible.entry(name.clone()).or_default(); |
157 | let existing_import_type = existing_import_map.entry(name).or_insert(def_import_type); | ||
129 | 158 | ||
130 | macro_rules! check_changed { | 159 | macro_rules! check_changed { |
131 | ($changed:ident, ($existing:ident/$def:ident).$field:ident) => { | 160 | ($changed:ident, ($existing:ident/$def:ident).$field:ident, $existing_import_type:ident, $def_import_type:ident) => { |
132 | match ($existing.$field, $def.$field) { | 161 | match ($existing.$field, $def.$field) { |
133 | (None, Some(_)) => { | 162 | (None, Some(_)) => { |
134 | $existing.from_glob = $def.from_glob; | 163 | *existing_import_type = $def_import_type; |
135 | $existing.$field = $def.$field; | 164 | $existing.$field = $def.$field; |
136 | $changed = true; | 165 | $changed = true; |
137 | } | 166 | } |
138 | // Only update if the new def came from a specific import and the existing | 167 | (Some(_), Some(_)) |
139 | // import came from a glob import. | 168 | if $existing_import_type.is_glob() && $def_import_type.is_named() => |
140 | (Some(_), Some(_)) if $existing.from_glob && !$def.from_glob => { | 169 | { |
141 | mark::hit!(import_shadowed); | 170 | mark::hit!(import_shadowed); |
142 | $existing.from_glob = $def.from_glob; | 171 | *$existing_import_type = $def_import_type; |
143 | $existing.$field = $def.$field; | 172 | $existing.$field = $def.$field; |
144 | $changed = true; | 173 | $changed = true; |
145 | } | 174 | } |
@@ -148,9 +177,9 @@ impl ItemScope { | |||
148 | }; | 177 | }; |
149 | } | 178 | } |
150 | 179 | ||
151 | check_changed!(changed, (existing / def).types); | 180 | check_changed!(changed, (existing / def).types, existing_import_type, def_import_type); |
152 | check_changed!(changed, (existing / def).values); | 181 | check_changed!(changed, (existing / def).values, existing_import_type, def_import_type); |
153 | check_changed!(changed, (existing / def).macros); | 182 | check_changed!(changed, (existing / def).macros, existing_import_type, def_import_type); |
154 | 183 | ||
155 | changed | 184 | changed |
156 | } | 185 | } |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 93f58e2c7..f7b99e0be 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -20,6 +20,7 @@ use test_utils::mark; | |||
20 | use crate::{ | 20 | use crate::{ |
21 | attr::Attrs, | 21 | attr::Attrs, |
22 | db::DefDatabase, | 22 | db::DefDatabase, |
23 | item_scope::ImportType, | ||
23 | item_tree::{ | 24 | item_tree::{ |
24 | self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind, | 25 | self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind, |
25 | }, | 26 | }, |
@@ -80,6 +81,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> Cr | |||
80 | mod_dirs: FxHashMap::default(), | 81 | mod_dirs: FxHashMap::default(), |
81 | cfg_options, | 82 | cfg_options, |
82 | proc_macros, | 83 | proc_macros, |
84 | import_types: FxHashMap::default(), | ||
83 | }; | 85 | }; |
84 | collector.collect(); | 86 | collector.collect(); |
85 | collector.finish() | 87 | collector.finish() |
@@ -186,6 +188,7 @@ struct DefCollector<'a> { | |||
186 | mod_dirs: FxHashMap<LocalModuleId, ModDir>, | 188 | mod_dirs: FxHashMap<LocalModuleId, ModDir>, |
187 | cfg_options: &'a CfgOptions, | 189 | cfg_options: &'a CfgOptions, |
188 | proc_macros: Vec<(Name, ProcMacroExpander)>, | 190 | proc_macros: Vec<(Name, ProcMacroExpander)>, |
191 | import_types: FxHashMap<Name, ImportType>, | ||
189 | } | 192 | } |
190 | 193 | ||
191 | impl DefCollector<'_> { | 194 | impl DefCollector<'_> { |
@@ -305,7 +308,7 @@ impl DefCollector<'_> { | |||
305 | self.def_map.root, | 308 | self.def_map.root, |
306 | &[(name, PerNs::macros(macro_, Visibility::Public))], | 309 | &[(name, PerNs::macros(macro_, Visibility::Public))], |
307 | Visibility::Public, | 310 | Visibility::Public, |
308 | false, | 311 | ImportType::Named, |
309 | ); | 312 | ); |
310 | } | 313 | } |
311 | } | 314 | } |
@@ -331,7 +334,7 @@ impl DefCollector<'_> { | |||
331 | self.def_map.root, | 334 | self.def_map.root, |
332 | &[(name, PerNs::macros(macro_, Visibility::Public))], | 335 | &[(name, PerNs::macros(macro_, Visibility::Public))], |
333 | Visibility::Public, | 336 | Visibility::Public, |
334 | false, | 337 | ImportType::Named, |
335 | ); | 338 | ); |
336 | } | 339 | } |
337 | 340 | ||
@@ -478,7 +481,7 @@ impl DefCollector<'_> { | |||
478 | .filter(|(_, res)| !res.is_none()) | 481 | .filter(|(_, res)| !res.is_none()) |
479 | .collect::<Vec<_>>(); | 482 | .collect::<Vec<_>>(); |
480 | 483 | ||
481 | self.update(module_id, &items, vis, true); | 484 | self.update(module_id, &items, vis, ImportType::Glob); |
482 | } else { | 485 | } else { |
483 | // glob import from same crate => we do an initial | 486 | // glob import from same crate => we do an initial |
484 | // import, and then need to propagate any further | 487 | // import, and then need to propagate any further |
@@ -500,7 +503,7 @@ impl DefCollector<'_> { | |||
500 | .filter(|(_, res)| !res.is_none()) | 503 | .filter(|(_, res)| !res.is_none()) |
501 | .collect::<Vec<_>>(); | 504 | .collect::<Vec<_>>(); |
502 | 505 | ||
503 | self.update(module_id, &items, vis, true); | 506 | self.update(module_id, &items, vis, ImportType::Glob); |
504 | // record the glob import in case we add further items | 507 | // record the glob import in case we add further items |
505 | let glob = self.glob_imports.entry(m.local_id).or_default(); | 508 | let glob = self.glob_imports.entry(m.local_id).or_default(); |
506 | if !glob.iter().any(|(mid, _)| *mid == module_id) { | 509 | if !glob.iter().any(|(mid, _)| *mid == module_id) { |
@@ -530,7 +533,7 @@ impl DefCollector<'_> { | |||
530 | (name, res) | 533 | (name, res) |
531 | }) | 534 | }) |
532 | .collect::<Vec<_>>(); | 535 | .collect::<Vec<_>>(); |
533 | self.update(module_id, &resolutions, vis, true); | 536 | self.update(module_id, &resolutions, vis, ImportType::Glob); |
534 | } | 537 | } |
535 | Some(d) => { | 538 | Some(d) => { |
536 | log::debug!("glob import {:?} from non-module/enum {:?}", import, d); | 539 | log::debug!("glob import {:?} from non-module/enum {:?}", import, d); |
@@ -556,7 +559,7 @@ impl DefCollector<'_> { | |||
556 | } | 559 | } |
557 | } | 560 | } |
558 | 561 | ||
559 | self.update(module_id, &[(name, def)], vis, false); | 562 | self.update(module_id, &[(name, def)], vis, ImportType::Named); |
560 | } | 563 | } |
561 | None => mark::hit!(bogus_paths), | 564 | None => mark::hit!(bogus_paths), |
562 | } | 565 | } |
@@ -568,9 +571,9 @@ impl DefCollector<'_> { | |||
568 | module_id: LocalModuleId, | 571 | module_id: LocalModuleId, |
569 | resolutions: &[(Name, PerNs)], | 572 | resolutions: &[(Name, PerNs)], |
570 | vis: Visibility, | 573 | vis: Visibility, |
571 | is_from_glob: bool, | 574 | import_type: ImportType, |
572 | ) { | 575 | ) { |
573 | self.update_recursive(module_id, resolutions, vis, is_from_glob, 0) | 576 | self.update_recursive(module_id, resolutions, vis, import_type, 0) |
574 | } | 577 | } |
575 | 578 | ||
576 | fn update_recursive( | 579 | fn update_recursive( |
@@ -582,7 +585,7 @@ impl DefCollector<'_> { | |||
582 | vis: Visibility, | 585 | vis: Visibility, |
583 | // All resolutions are imported with this glob status; the glob status | 586 | // All resolutions are imported with this glob status; the glob status |
584 | // in the `PerNs` values are ignored and overwritten | 587 | // in the `PerNs` values are ignored and overwritten |
585 | is_from_glob: bool, | 588 | import_type: ImportType, |
586 | depth: usize, | 589 | depth: usize, |
587 | ) { | 590 | ) { |
588 | if depth > 100 { | 591 | if depth > 100 { |
@@ -592,8 +595,12 @@ impl DefCollector<'_> { | |||
592 | let scope = &mut self.def_map.modules[module_id].scope; | 595 | let scope = &mut self.def_map.modules[module_id].scope; |
593 | let mut changed = false; | 596 | let mut changed = false; |
594 | for (name, res) in resolutions { | 597 | for (name, res) in resolutions { |
595 | changed |= | 598 | changed |= scope.push_res( |
596 | scope.push_res(name.clone(), res.with_visibility(vis).from_glob(is_from_glob)); | 599 | &mut self.import_types, |
600 | name.clone(), | ||
601 | res.with_visibility(vis), | ||
602 | import_type, | ||
603 | ); | ||
597 | } | 604 | } |
598 | 605 | ||
599 | if !changed { | 606 | if !changed { |
@@ -616,7 +623,7 @@ impl DefCollector<'_> { | |||
616 | glob_importing_module, | 623 | glob_importing_module, |
617 | resolutions, | 624 | resolutions, |
618 | glob_import_vis, | 625 | glob_import_vis, |
619 | true, | 626 | ImportType::Glob, |
620 | depth + 1, | 627 | depth + 1, |
621 | ); | 628 | ); |
622 | } | 629 | } |
@@ -940,7 +947,7 @@ impl ModCollector<'_, '_> { | |||
940 | self.module_id, | 947 | self.module_id, |
941 | &[(name.clone(), PerNs::from_def(id, vis, has_constructor))], | 948 | &[(name.clone(), PerNs::from_def(id, vis, has_constructor))], |
942 | vis, | 949 | vis, |
943 | false, | 950 | ImportType::Named, |
944 | ) | 951 | ) |
945 | } | 952 | } |
946 | } | 953 | } |
@@ -1047,7 +1054,7 @@ impl ModCollector<'_, '_> { | |||
1047 | self.module_id, | 1054 | self.module_id, |
1048 | &[(name, PerNs::from_def(def, vis, false))], | 1055 | &[(name, PerNs::from_def(def, vis, false))], |
1049 | vis, | 1056 | vis, |
1050 | false, | 1057 | ImportType::Named, |
1051 | ); | 1058 | ); |
1052 | res | 1059 | res |
1053 | } | 1060 | } |
@@ -1177,6 +1184,7 @@ mod tests { | |||
1177 | mod_dirs: FxHashMap::default(), | 1184 | mod_dirs: FxHashMap::default(), |
1178 | cfg_options: &CfgOptions::default(), | 1185 | cfg_options: &CfgOptions::default(), |
1179 | proc_macros: Default::default(), | 1186 | proc_macros: Default::default(), |
1187 | import_types: FxHashMap::default(), | ||
1180 | }; | 1188 | }; |
1181 | collector.collect(); | 1189 | collector.collect(); |
1182 | collector.def_map | 1190 | collector.def_map |
diff --git a/crates/ra_hir_def/src/per_ns.rs b/crates/ra_hir_def/src/per_ns.rs index e5cbca71d..74665c588 100644 --- a/crates/ra_hir_def/src/per_ns.rs +++ b/crates/ra_hir_def/src/per_ns.rs | |||
@@ -9,7 +9,6 @@ use crate::{item_scope::ItemInNs, visibility::Visibility, ModuleDefId}; | |||
9 | 9 | ||
10 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 10 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
11 | pub struct PerNs { | 11 | pub struct PerNs { |
12 | pub from_glob: bool, | ||
13 | pub types: Option<(ModuleDefId, Visibility)>, | 12 | pub types: Option<(ModuleDefId, Visibility)>, |
14 | pub values: Option<(ModuleDefId, Visibility)>, | 13 | pub values: Option<(ModuleDefId, Visibility)>, |
15 | pub macros: Option<(MacroDefId, Visibility)>, | 14 | pub macros: Option<(MacroDefId, Visibility)>, |
@@ -17,29 +16,29 @@ pub struct PerNs { | |||
17 | 16 | ||
18 | impl Default for PerNs { | 17 | impl Default for PerNs { |
19 | fn default() -> Self { | 18 | fn default() -> Self { |
20 | PerNs { from_glob: false, types: None, values: None, macros: None } | 19 | PerNs { types: None, values: None, macros: None } |
21 | } | 20 | } |
22 | } | 21 | } |
23 | 22 | ||
24 | impl PerNs { | 23 | impl PerNs { |
25 | pub fn none() -> PerNs { | 24 | pub fn none() -> PerNs { |
26 | PerNs { from_glob: false, types: None, values: None, macros: None } | 25 | PerNs { types: None, values: None, macros: None } |
27 | } | 26 | } |
28 | 27 | ||
29 | pub fn values(t: ModuleDefId, v: Visibility) -> PerNs { | 28 | pub fn values(t: ModuleDefId, v: Visibility) -> PerNs { |
30 | PerNs { from_glob: false, types: None, values: Some((t, v)), macros: None } | 29 | PerNs { types: None, values: Some((t, v)), macros: None } |
31 | } | 30 | } |
32 | 31 | ||
33 | pub fn types(t: ModuleDefId, v: Visibility) -> PerNs { | 32 | pub fn types(t: ModuleDefId, v: Visibility) -> PerNs { |
34 | PerNs { from_glob: false, types: Some((t, v)), values: None, macros: None } | 33 | PerNs { types: Some((t, v)), values: None, macros: None } |
35 | } | 34 | } |
36 | 35 | ||
37 | pub fn both(types: ModuleDefId, values: ModuleDefId, v: Visibility) -> PerNs { | 36 | pub fn both(types: ModuleDefId, values: ModuleDefId, v: Visibility) -> PerNs { |
38 | PerNs { from_glob: false, types: Some((types, v)), values: Some((values, v)), macros: None } | 37 | PerNs { types: Some((types, v)), values: Some((values, v)), macros: None } |
39 | } | 38 | } |
40 | 39 | ||
41 | pub fn macros(macro_: MacroDefId, v: Visibility) -> PerNs { | 40 | pub fn macros(macro_: MacroDefId, v: Visibility) -> PerNs { |
42 | PerNs { from_glob: false, types: None, values: None, macros: Some((macro_, v)) } | 41 | PerNs { types: None, values: None, macros: Some((macro_, v)) } |
43 | } | 42 | } |
44 | 43 | ||
45 | pub fn is_none(&self) -> bool { | 44 | pub fn is_none(&self) -> bool { |
@@ -64,7 +63,6 @@ impl PerNs { | |||
64 | 63 | ||
65 | pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNs { | 64 | pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNs { |
66 | PerNs { | 65 | PerNs { |
67 | from_glob: self.from_glob, | ||
68 | types: self.types.filter(|(_, v)| f(*v)), | 66 | types: self.types.filter(|(_, v)| f(*v)), |
69 | values: self.values.filter(|(_, v)| f(*v)), | 67 | values: self.values.filter(|(_, v)| f(*v)), |
70 | macros: self.macros.filter(|(_, v)| f(*v)), | 68 | macros: self.macros.filter(|(_, v)| f(*v)), |
@@ -73,7 +71,6 @@ impl PerNs { | |||
73 | 71 | ||
74 | pub fn with_visibility(self, vis: Visibility) -> PerNs { | 72 | pub fn with_visibility(self, vis: Visibility) -> PerNs { |
75 | PerNs { | 73 | PerNs { |
76 | from_glob: self.from_glob, | ||
77 | types: self.types.map(|(it, _)| (it, vis)), | 74 | types: self.types.map(|(it, _)| (it, vis)), |
78 | values: self.values.map(|(it, _)| (it, vis)), | 75 | values: self.values.map(|(it, _)| (it, vis)), |
79 | macros: self.macros.map(|(it, _)| (it, vis)), | 76 | macros: self.macros.map(|(it, _)| (it, vis)), |
@@ -82,7 +79,6 @@ impl PerNs { | |||
82 | 79 | ||
83 | pub fn or(self, other: PerNs) -> PerNs { | 80 | pub fn or(self, other: PerNs) -> PerNs { |
84 | PerNs { | 81 | PerNs { |
85 | from_glob: self.from_glob, | ||
86 | types: self.types.or(other.types), | 82 | types: self.types.or(other.types), |
87 | values: self.values.or(other.values), | 83 | values: self.values.or(other.values), |
88 | macros: self.macros.or(other.macros), | 84 | macros: self.macros.or(other.macros), |
@@ -96,8 +92,4 @@ impl PerNs { | |||
96 | .chain(self.values.map(|it| ItemInNs::Values(it.0)).into_iter()) | 92 | .chain(self.values.map(|it| ItemInNs::Values(it.0)).into_iter()) |
97 | .chain(self.macros.map(|it| ItemInNs::Macros(it.0)).into_iter()) | 93 | .chain(self.macros.map(|it| ItemInNs::Macros(it.0)).into_iter()) |
98 | } | 94 | } |
99 | |||
100 | pub fn from_glob(self, from_glob: bool) -> PerNs { | ||
101 | PerNs { from_glob, ..self } | ||
102 | } | ||
103 | } | 95 | } |