vhdl_lang/named_entity/
visibility.rs1use crate::ast::*;
7use crate::named_entity::*;
8
9use fnv::FnvHashMap;
10use std::collections::hash_map::Entry;
11
12#[derive(Clone, Debug)]
13struct VisibleEntity<'a> {
14 visible_pos: Vec<Option<SrcPos>>,
16 entity: EntRef<'a>,
17}
18
19#[derive(Debug)]
20pub enum ConflictingName {
21 MadeVisible,
22 Declared,
23}
24
25#[derive(Debug)]
26pub struct IntoUnambiguousError {
27 designator: Designator,
28 conflicting_names: Vec<(SrcPos, ConflictingName)>,
29}
30
31impl IntoUnambiguousError {
32 pub fn new(designator: Designator) -> IntoUnambiguousError {
33 IntoUnambiguousError {
34 designator,
35 conflicting_names: Vec::new(),
36 }
37 }
38
39 pub fn add_conflicting(&mut self, pos: SrcPos, name: ConflictingName) {
40 self.conflicting_names.push((pos, name))
41 }
42
43 pub fn into_diagnostic(self, ctx: &dyn TokenAccess, span: TokenSpan) -> Diagnostic {
44 let mut error = Diagnostic::new(
45 span.pos(ctx),
46 format!(
47 "Name '{}' is hidden by conflicting use clause",
48 self.designator
49 ),
50 ErrorCode::ConflictingUseClause,
51 );
52 for (pos, name) in self.conflicting_names {
53 let msg = match name {
54 ConflictingName::MadeVisible => {
55 format!("Conflicting name '{}' made visible here", self.designator)
56 }
57 ConflictingName::Declared => {
58 format!("Conflicting name '{}' declared here", self.designator)
59 }
60 };
61 error.add_related(pos, msg)
62 }
63 error
64 }
65}
66
67impl<'a> VisibleEntity<'a> {
68 fn clone_with_more_visiblity(&self, visible_pos: Option<&SrcPos>) -> VisibleEntity<'a> {
69 let mut more = self.clone();
70 more.visible_pos.push(visible_pos.cloned());
71 more
72 }
73}
74
75#[derive(Clone)]
76pub struct VisibleRegion<'a> {
77 visible_pos: Vec<Option<SrcPos>>,
79 region: &'a Region<'a>,
80}
81
82impl<'a> VisibleRegion<'a> {
83 fn clone_with_more_visiblity(&self, visible_pos: Option<&SrcPos>) -> VisibleRegion<'a> {
85 let mut more = self.clone();
86 more.visible_pos.push(visible_pos.cloned());
87 more
88 }
89
90 pub fn region(&self) -> &Region<'a> {
91 self.region
92 }
93}
94
95#[derive(Clone, Default)]
96pub struct Visibility<'a> {
97 all_in_regions: Vec<VisibleRegion<'a>>,
99 visible: FnvHashMap<Designator, FnvHashMap<EntityId, VisibleEntity<'a>>>,
100}
101
102impl<'a> Visibility<'a> {
103 pub fn make_all_potentially_visible(
104 &mut self,
105 visible_pos: Option<&SrcPos>,
106 region: &'a Region<'a>,
107 ) {
108 self.all_in_regions.push(VisibleRegion {
109 visible_pos: vec![visible_pos.cloned()],
110 region,
111 });
112 }
113
114 pub fn all_in_region(&self) -> impl Iterator<Item = &VisibleRegion<'a>> {
115 self.all_in_regions.iter()
116 }
117
118 pub fn visible(&self) -> impl Iterator<Item = EntRef<'a>> + '_ {
119 self.visible.values().flatten().map(|entry| entry.1.entity)
120 }
121
122 pub fn add_context_visibility(
123 &mut self,
124 visible_pos: Option<&SrcPos>,
125 visibility: &Visibility<'a>,
126 ) {
127 for visible_region in visibility.all_in_regions.iter() {
128 self.all_in_regions
129 .push(visible_region.clone_with_more_visiblity(visible_pos));
130 }
131
132 for (designator, visibile) in visibility.visible.iter() {
133 for visible_ent in visibile.values() {
134 self.insert(
136 designator.clone(),
137 visible_ent.clone_with_more_visiblity(visible_pos),
138 );
139 }
140 }
141 }
142
143 pub fn make_potentially_visible_with_name(
144 &mut self,
145 visible_pos: Option<&SrcPos>,
146 designator: Designator,
147 ent: EntRef<'a>,
148 ) {
149 for entity in ent.as_actual().implicits.iter() {
152 self.make_potentially_visible_with_name(
153 visible_pos,
154 entity.designator().clone(),
155 entity,
156 );
157 }
158
159 let visible_ent = VisibleEntity {
160 visible_pos: vec![visible_pos.cloned()],
161 entity: ent,
162 };
163
164 self.insert(designator, visible_ent);
165 }
166
167 fn insert(&mut self, designator: Designator, visible_ent: VisibleEntity<'a>) {
168 match self.visible.entry(designator) {
169 Entry::Vacant(entry) => {
170 let mut map = FnvHashMap::default();
171 map.insert(visible_ent.entity.id(), visible_ent);
172 entry.insert(map);
173 }
174 Entry::Occupied(mut entry) => {
175 entry.get_mut().insert(visible_ent.entity.id(), visible_ent);
176 }
177 }
178 }
179
180 pub fn lookup_into(&self, designator: &Designator, visible: &mut Visible<'a>) {
182 for visible_region in self.all_in_regions.iter() {
183 if let Some(named_entities) = visible_region.region.lookup_immediate(designator) {
184 match named_entities {
185 NamedEntities::Single(entity) => {
186 visible.insert(visible_region.visible_pos.clone(), entity);
187 }
188 NamedEntities::Overloaded(overloaded) => {
189 for entity in overloaded.entities() {
190 visible.insert(visible_region.visible_pos.clone(), entity.into());
191 }
192 }
193 }
194 }
195 }
196
197 if let Some(visible_entities) = self.visible.get(designator) {
198 for visible_entity in visible_entities.values() {
199 visible.insert(visible_entity.visible_pos.clone(), visible_entity.entity);
200 }
201 }
202 }
203}
204
205#[derive(Default, Debug)]
206pub struct Visible<'a> {
207 visible_entities: FnvHashMap<EntityId, VisibleEntity<'a>>,
208}
209
210impl<'a> Visible<'a> {
211 fn insert(&mut self, visible_pos: Vec<Option<SrcPos>>, entity: EntRef<'a>) {
212 let actual_entity = entity.as_actual();
213
214 match self.visible_entities.entry(actual_entity.id()) {
215 Entry::Vacant(entry) => {
216 entry.insert(VisibleEntity {
217 visible_pos,
218 entity,
219 });
220 }
221 Entry::Occupied(mut entry) => {
222 let old_entity = &entry.get().entity;
223 if entity.is_alias_of(old_entity) {
224 entry.insert(VisibleEntity {
226 visible_pos,
227 entity,
228 });
229 }
230 }
231 };
232 }
233
234 pub fn into_unambiguous(
235 self,
236 designator: &Designator,
237 ) -> Result<Option<NamedEntities<'a>>, IntoUnambiguousError> {
238 let mut named_entities: Vec<_> = self
239 .visible_entities
240 .values()
241 .map(|ent| ent.entity)
242 .collect();
243
244 if named_entities.is_empty() {
245 Ok(None)
246 } else if named_entities.iter().all(|ent| ent.is_overloaded()) {
247 Ok(Some(NamedEntities::new_overloaded(
248 named_entities
249 .into_iter()
250 .map(|ent| OverloadedEnt::from_any(ent).unwrap())
251 .collect(),
252 )))
253 } else if named_entities.len() == 1 {
254 Ok(Some(NamedEntities::new(named_entities.pop().unwrap())))
255 } else {
256 let mut error = IntoUnambiguousError::new(designator.clone());
257 fn last_visible_pos(visible_entity: &VisibleEntity<'_>) -> u32 {
260 if let Some(pos) = visible_entity.visible_pos.iter().rev().flatten().next() {
261 return pos.range().start.line;
262 }
263 0
264 }
265
266 let mut visible_entities: Vec<_> = self.visible_entities.values().collect();
268 visible_entities.sort_by_key(|ent| last_visible_pos(ent));
269
270 for visible_entity in visible_entities {
271 for visible_pos in visible_entity.visible_pos.iter().rev().flatten() {
272 error.add_conflicting(visible_pos.clone(), ConflictingName::MadeVisible);
273 }
274 if let Some(pos) = visible_entity.entity.decl_pos() {
275 error.add_conflicting(pos.clone(), ConflictingName::Declared);
276 }
277 }
278
279 Err(error)
280 }
281 }
282}