1use std::collections::hash_map;
2use std::ops::Range;
3use std::rc::Rc;
4
5use rustc_hash::FxHashMap;
6
7use super::saved_names::{NameTables, SavedNames};
8use super::{Scope, ScopeSet};
9use crate::core::{BindingId, Namespace};
10use crate::reader::Symbol;
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
13pub enum Phase {
14 Runtime,
15 CompileTime,
16}
17
18#[derive(Clone, Debug, PartialEq, Eq)]
19pub enum Resolution {
20 Bound(BindingId),
21 Unbound,
22 Ambiguous(Vec<BindingId>),
23}
24
25#[derive(serde::Serialize, serde::Deserialize)]
26struct Entry {
27 scopes: ScopeSet,
28 binding: BindingId,
29 phase: Phase,
30}
31
32impl Entry {
33 fn is_visible_from_scopes(&self, scopes: &ScopeSet, phase: Phase) -> bool {
34 self.phase_matches(phase) && self.scopes.is_subset_of(scopes)
35 }
36
37 fn is_visible_from_plain_scopes(&self, scopes: &ScopeSet, phase: Phase) -> bool {
38 self.phase_matches(phase) && self.scopes.is_plain_subset_of(scopes)
39 }
40
41 fn phase_matches(&self, phase: Phase) -> bool {
42 phase == Phase::CompileTime || self.phase == Phase::Runtime
43 }
44
45 fn anchor(&self) -> Option<Scope> {
46 self.scopes.plain_largest()
47 }
48}
49
50#[derive(Default, serde::Serialize, serde::Deserialize)]
51pub(super) struct NameEntries {
52 plain_sorted_by_anchor: Vec<Entry>,
53 sharing: Vec<Entry>,
54}
55
56impl NameEntries {
57 const SHORT_LIST_LENGTH: usize = 16;
58
59 fn bind(
60 &mut self,
61 scopes: &ScopeSet,
62 binding: BindingId,
63 phase: Phase,
64 ) -> Result<(), BindingId> {
65 if !self.is_plain_search(scopes) {
66 return self.bind_sharing(scopes, binding, phase);
67 }
68 let anchored_end = self.anchored_end(scopes.plain_largest());
69 match self.entry_with_scopes(anchored_end, scopes) {
70 Some(existing) => Self::existing(existing, binding),
71 None => {
72 let entry = Entry {
73 scopes: scopes.clone(),
74 binding,
75 phase,
76 };
77 self.plain_sorted_by_anchor.insert(anchored_end, entry);
78 Ok(())
79 }
80 }
81 }
82
83 fn existing(existing: &Entry, binding: BindingId) -> Result<(), BindingId> {
84 if existing.binding == binding {
85 Ok(())
86 } else {
87 Err(existing.binding)
88 }
89 }
90
91 #[inline(never)]
92 fn bind_sharing(
93 &mut self,
94 scopes: &ScopeSet,
95 binding: BindingId,
96 phase: Phase,
97 ) -> Result<(), BindingId> {
98 if let Some(existing) = self.all().find(|entry| entry.scopes == *scopes) {
99 return Self::existing(existing, binding);
100 }
101 let entry = Entry {
102 scopes: scopes.clone(),
103 binding,
104 phase,
105 };
106 if scopes.is_plain() {
107 let anchored_end = self.anchored_end(scopes.plain_largest());
108 self.plain_sorted_by_anchor.insert(anchored_end, entry);
109 } else {
110 self.sharing.push(entry);
111 }
112 Ok(())
113 }
114
115 fn anchored_end(&self, anchor: Option<Scope>) -> usize {
116 self.plain_sorted_by_anchor
117 .partition_point(|entry| entry.anchor() <= anchor)
118 }
119
120 fn entry_with_scopes(&self, anchored_end: usize, scopes: &ScopeSet) -> Option<&Entry> {
121 let anchor = scopes.plain_largest();
122 self.plain_sorted_by_anchor[..anchored_end]
123 .iter()
124 .rev()
125 .take_while(|entry| entry.anchor() == anchor)
126 .find(|entry| entry.scopes == *scopes)
127 }
128
129 fn visible(&self, scopes: &ScopeSet, phase: Phase) -> Vec<&Entry> {
130 let mut visible = Vec::new();
131 self.visit_visible(scopes, phase, |entry| visible.push(entry));
132 visible
133 }
134
135 fn visit_visible<'entries>(
136 &'entries self,
137 scopes: &ScopeSet,
138 phase: Phase,
139 visit: impl FnMut(&'entries Entry),
140 ) {
141 if self.is_plain_search(scopes) {
142 self.visit_plain_visible(scopes, phase, visit);
143 } else {
144 self.visit_visible_sharing(scopes, phase, visit);
145 }
146 }
147
148 fn is_plain_search(&self, scopes: &ScopeSet) -> bool {
149 self.sharing.is_empty() && scopes.is_plain()
150 }
151
152 fn visit_plain_visible<'entries>(
153 &'entries self,
154 scopes: &ScopeSet,
155 phase: Phase,
156 mut visit: impl FnMut(&'entries Entry),
157 ) {
158 let mut visit_if_visible = |entry: &'entries Entry| {
159 if entry.is_visible_from_plain_scopes(scopes, phase) {
160 visit(entry);
161 }
162 };
163 if self.is_shorter_than_an_anchor_search(scopes) {
164 self.plain_sorted_by_anchor
165 .iter()
166 .for_each(visit_if_visible);
167 return;
168 }
169 for anchor in Self::possible_anchors(scopes) {
170 self.plain_sorted_by_anchor[self.anchored(anchor)]
171 .iter()
172 .for_each(&mut visit_if_visible);
173 }
174 }
175
176 #[inline(never)]
177 fn visit_visible_sharing<'entries>(
178 &'entries self,
179 scopes: &ScopeSet,
180 phase: Phase,
181 visit: impl FnMut(&'entries Entry),
182 ) {
183 self.all()
184 .filter(|entry| entry.is_visible_from_scopes(scopes, phase))
185 .for_each(visit);
186 }
187
188 fn unbind(&mut self, binding: BindingId) {
189 self.plain_sorted_by_anchor
190 .retain(|entry| entry.binding != binding);
191 self.sharing.retain(|entry| entry.binding != binding);
192 }
193
194 fn forget(&mut self, forgotten: &impl Fn(BindingId) -> bool) {
195 self.plain_sorted_by_anchor
196 .retain(|entry| !forgotten(entry.binding));
197 self.sharing.retain(|entry| !forgotten(entry.binding));
198 }
199
200 fn is_empty(&self) -> bool {
201 self.plain_sorted_by_anchor.is_empty() && self.sharing.is_empty()
202 }
203
204 pub(super) fn is_within(&self, scopes: &Range<Scope>) -> bool {
205 self.all()
206 .all(|entry| entry.scopes.iter().any(|scope| scopes.contains(&scope)))
207 }
208
209 fn all(&self) -> impl Iterator<Item = &Entry> {
210 self.plain_sorted_by_anchor.iter().chain(&self.sharing)
211 }
212
213 fn is_shorter_than_an_anchor_search(&self, scopes: &ScopeSet) -> bool {
214 self.plain_sorted_by_anchor.len() <= scopes.plain_len().max(Self::SHORT_LIST_LENGTH)
215 }
216
217 fn anchored(&self, anchor: Option<Scope>) -> Range<usize> {
218 let start = self
219 .plain_sorted_by_anchor
220 .partition_point(|entry| entry.anchor() < anchor);
221 let length =
222 self.plain_sorted_by_anchor[start..].partition_point(|entry| entry.anchor() == anchor);
223 start..start + length
224 }
225
226 fn possible_anchors(scopes: &ScopeSet) -> impl Iterator<Item = Option<Scope>> + '_ {
227 std::iter::once(None).chain(scopes.plain_iter().map(Some))
228 }
229}
230
231#[derive(Default, serde::Serialize, serde::Deserialize)]
232pub struct BindingTable {
233 #[serde(skip)]
234 saved: SavedNames,
235 entries: FxHashMap<(Rc<str>, Namespace), NameEntries>,
236 qualified_names: QualifiedNames,
237}
238
239impl BindingTable {
240 pub fn bind(
241 &mut self,
242 symbol: &Symbol,
243 namespace: Namespace,
244 binding: BindingId,
245 phase: Phase,
246 ) -> Result<(), BindingId> {
247 let entries = match self.entries.entry((symbol.shared_name(), namespace)) {
248 hash_map::Entry::Occupied(occupied) => occupied.into_mut(),
249 hash_map::Entry::Vacant(vacant) => {
250 self.qualified_names.record(vacant.key());
251 vacant.insert(NameEntries::default())
252 }
253 };
254 entries.bind(symbol.scopes(), binding, phase)
255 }
256
257 pub fn unbind(&mut self, symbol: &Symbol, namespace: Namespace, binding: BindingId) {
258 if let Some(entries) = self.entries.get_mut(&(symbol.shared_name(), namespace)) {
259 entries.unbind(binding);
260 }
261 }
262
263 pub fn forget(&mut self, forgotten: impl Fn(BindingId) -> bool) {
264 for entries in self.entries.values_mut() {
265 entries.forget(&forgotten);
266 }
267 self.entries.retain(|_, entries| !entries.is_empty());
268 }
269
270 #[cfg(test)]
271 pub fn holds(&self, binding: BindingId) -> bool {
272 let saved = self.saved.all().map(|(_, _, entries)| entries);
273 let mut all = self
274 .entries
275 .values()
276 .chain(saved)
277 .flat_map(NameEntries::all);
278 all.any(|entry| entry.binding == binding)
279 }
280
281 pub fn resolve(&self, symbol: &Symbol, namespace: Namespace, phase: Phase) -> Resolution {
282 let mut largest = LargestCandidates::default();
283 for entries in self.entries_named(
284 symbol.scopes(),
285 symbol.name(),
286 symbol.shared_name(),
287 namespace,
288 ) {
289 entries.visit_visible(symbol.scopes(), phase, |entry| largest.consider(entry));
290 }
291 largest.resolution()
292 }
293
294 pub fn visible_name_bindings(
295 &self,
296 symbol: &Symbol,
297 namespace: Namespace,
298 phase: Phase,
299 ) -> Vec<(Rc<str>, BindingId)> {
300 let own = self
301 .entries
302 .iter()
303 .map(|((name, entry_namespace), entries)| (Rc::clone(name), *entry_namespace, entries));
304 own.chain(self.saved.all())
305 .filter(|(_, entry_namespace, _)| *entry_namespace == namespace)
306 .flat_map(|(name, _, entries)| {
307 entries
308 .visible(symbol.scopes(), phase)
309 .into_iter()
310 .map(move |entry| (Rc::clone(&name), entry.binding))
311 })
312 .collect()
313 }
314
315 pub fn visible_bindings(
316 &self,
317 scopes: &ScopeSet,
318 namespace: Namespace,
319 phase: Phase,
320 ) -> Vec<BindingId> {
321 let own = self
322 .entries
323 .iter()
324 .filter(|((_, entry_namespace), _)| *entry_namespace == namespace)
325 .map(|(_, entries)| entries);
326 own.chain(self.saved.all_of(namespace))
327 .flat_map(|entries| entries.visible(scopes, phase))
328 .map(|entry| entry.binding)
329 .collect()
330 }
331
332 pub fn visible_qualified_bindings_ending_in(
333 &self,
334 last_segment: &Symbol,
335 namespace: Namespace,
336 phase: Phase,
337 ) -> Vec<BindingId> {
338 let mut visible = Vec::new();
339 for name in self
340 .qualified_names
341 .ending_in(last_segment.shared_name(), namespace)
342 {
343 for entries in
344 self.entries_named(last_segment.scopes(), name, Rc::clone(name), namespace)
345 {
346 entries.visit_visible(last_segment.scopes(), phase, |entry| {
347 visible.push(entry.binding);
348 });
349 }
350 }
351 visible
352 }
353
354 pub fn take_saved(&mut self, prelude_scopes: Range<Scope>) -> NameTables {
355 let entries = std::mem::take(&mut self.entries);
356 let keyed = entries
357 .into_iter()
358 .map(|((name, namespace), entries)| (name, namespace, entries));
359 NameTables::of(keyed.collect(), prelude_scopes)
360 }
361
362 pub fn adopt_saved(&mut self, saved: SavedNames) {
363 self.saved = saved;
364 }
365
366 fn entries_named(
367 &self,
368 scopes: &ScopeSet,
369 name: &str,
370 shared: Rc<str>,
371 namespace: Namespace,
372 ) -> impl Iterator<Item = &NameEntries> {
373 let own = self.entries.get(&(shared, namespace));
374 let saved = self.saved.entries_seen_from(scopes, name, namespace);
375 own.into_iter().chain(saved)
376 }
377}
378
379#[derive(Default, serde::Serialize, serde::Deserialize)]
380struct QualifiedNames {
381 by_last_segment: FxHashMap<(Rc<str>, Namespace), Vec<Rc<str>>>,
382}
383
384impl QualifiedNames {
385 const SEPARATOR: char = '/';
386
387 fn record(&mut self, (name, namespace): &(Rc<str>, Namespace)) {
388 if let Some((_, last_segment)) = name.rsplit_once(Self::SEPARATOR) {
389 let names = self
390 .by_last_segment
391 .entry((last_segment.into(), *namespace))
392 .or_default();
393 if !names.contains(name) {
394 names.push(Rc::clone(name));
395 }
396 }
397 }
398
399 fn ending_in(&self, last_segment: Rc<str>, namespace: Namespace) -> &[Rc<str>] {
400 self.by_last_segment
401 .get(&(last_segment, namespace))
402 .map_or(&[], Vec::as_slice)
403 }
404}
405
406#[derive(Default)]
407struct LargestCandidates {
408 size: usize,
409 first: Option<BindingId>,
410 others: Vec<BindingId>,
411}
412
413impl LargestCandidates {
414 fn consider(&mut self, entry: &Entry) {
415 let size = entry.scopes.len();
416 match self.first {
417 Some(_) if size < self.size => {}
418 Some(first) if size == self.size => self.add_equal(first, entry.binding),
419 _ => self.replace(size, entry.binding),
420 }
421 }
422
423 fn add_equal(&mut self, first: BindingId, binding: BindingId) {
424 if binding != first {
425 self.others.push(binding);
426 }
427 }
428
429 fn replace(&mut self, size: usize, binding: BindingId) {
430 self.size = size;
431 self.first = Some(binding);
432 self.others.clear();
433 }
434
435 fn resolution(self) -> Resolution {
436 match self.first {
437 None => Resolution::Unbound,
438 Some(binding) if self.others.is_empty() => Resolution::Bound(binding),
439 Some(binding) => Resolution::Ambiguous(Self::distinct(binding, self.others)),
440 }
441 }
442
443 fn distinct(first: BindingId, mut others: Vec<BindingId>) -> Vec<BindingId> {
444 others.push(first);
445 others.sort();
446 others.dedup();
447 others
448 }
449}
450
451#[cfg(test)]
452mod tests {
453 use super::*;
454 use crate::core::{BindingArena, BindingInfo, BindingKind};
455 use crate::scope::{ChainPrefix, Scope, ScopeAllocator, ScopeChain};
456
457 struct World {
458 table: BindingTable,
459 bindings: BindingArena,
460 scopes: ScopeAllocator,
461 }
462
463 impl World {
464 fn new() -> Self {
465 Self {
466 table: BindingTable::default(),
467 bindings: BindingArena::default(),
468 scopes: ScopeAllocator::default(),
469 }
470 }
471
472 fn scope(&mut self) -> Scope {
473 self.scopes.fresh()
474 }
475
476 fn save_names(&mut self) {
477 let first = ScopeAllocator::default().next_scope();
478 self.save_names_from(first);
479 }
480
481 fn save_names_from(&mut self, first: Scope) {
482 let prelude_scopes = first..self.scopes.next_scope();
483 let tables = self.table.take_saved(prelude_scopes);
484 let encoded = bincode::serialize(&tables).expect("the tables serialize");
485 let saved = bincode::deserialize(encoded.leak()).expect("the tables load");
486 self.table.adopt_saved(saved);
487 }
488
489 fn chain(&mut self, length: usize) -> ScopeChain {
490 let chain = ScopeChain::default();
491 (0..length).for_each(|_| chain.push(self.scope()));
492 chain
493 }
494
495 fn prefix(chain: &ScopeChain) -> ChainPrefix {
496 chain.prefix().expect("a test chain holds scopes")
497 }
498
499 fn sharing_symbol(name: &str, prefix: &ChainPrefix) -> Symbol {
500 let mut scopes = ScopeSet::default();
501 scopes.add_prefix(prefix);
502 Symbol::with_scopes(name, scopes)
503 }
504
505 fn define_sharing(&mut self, name: &str, prefix: &ChainPrefix) -> BindingId {
506 let binding = self.new_binding(name);
507 self.table
508 .bind(
509 &Self::sharing_symbol(name, prefix),
510 Namespace::Value,
511 binding,
512 Phase::Runtime,
513 )
514 .expect("no duplicate");
515 binding
516 }
517
518 fn new_binding(&mut self, name: &str) -> BindingId {
519 let info = BindingInfo::new(name.into(), BindingKind::Local, None);
520 self.bindings.add(info)
521 }
522
523 fn resolve_sharing(&self, name: &str, prefix: &ChainPrefix) -> Resolution {
524 self.table.resolve(
525 &Self::sharing_symbol(name, prefix),
526 Namespace::Value,
527 Phase::Runtime,
528 )
529 }
530
531 fn symbol(name: &str, scopes: &[Scope]) -> Symbol {
532 Symbol::with_scopes(name, Self::scope_set(scopes))
533 }
534
535 fn scope_set(scopes: &[Scope]) -> ScopeSet {
536 let mut set = ScopeSet::default();
537 scopes.iter().for_each(|scope| set.add(*scope));
538 set
539 }
540
541 fn define(&mut self, name: &str, scopes: &[Scope], phase: Phase) -> BindingId {
542 self.define_in(name, scopes, Namespace::Value, phase)
543 }
544
545 fn define_type(&mut self, name: &str, scopes: &[Scope]) -> BindingId {
546 self.define_in(name, scopes, Namespace::Type, Phase::Runtime)
547 }
548
549 fn define_in(
550 &mut self,
551 name: &str,
552 scopes: &[Scope],
553 namespace: Namespace,
554 phase: Phase,
555 ) -> BindingId {
556 let binding = self.new_binding(name);
557 let symbol = Self::symbol(name, scopes);
558 self.table
559 .bind(&symbol, namespace, binding, phase)
560 .expect("no duplicate");
561 binding
562 }
563
564 fn define_under_subsets(
565 &mut self,
566 name: &str,
567 scopes: &[Scope],
568 count: usize,
569 ) -> Vec<(Vec<Scope>, BindingId)> {
570 (0..count)
571 .map(|index| {
572 let subset = Self::subset(scopes, index);
573 let binding = self.define(name, &subset, Phase::Runtime);
574 (subset, binding)
575 })
576 .collect()
577 }
578
579 fn subset(scopes: &[Scope], index: usize) -> Vec<Scope> {
580 scopes
581 .iter()
582 .enumerate()
583 .filter(|(position, _)| index & (1 << position) != 0)
584 .map(|(_, scope)| *scope)
585 .collect()
586 }
587
588 fn visible(&self, scopes: &[Scope]) -> Vec<BindingId> {
589 let mut bindings = self.table.visible_bindings(
590 &Self::scope_set(scopes),
591 Namespace::Value,
592 Phase::Runtime,
593 );
594 bindings.sort();
595 bindings
596 }
597
598 fn visible_qualified_ending_in(
599 &self,
600 last_segment: &str,
601 scopes: &[Scope],
602 ) -> Vec<BindingId> {
603 let mut bindings = self.table.visible_qualified_bindings_ending_in(
604 &Self::symbol(last_segment, scopes),
605 Namespace::Value,
606 Phase::Runtime,
607 );
608 bindings.sort();
609 bindings
610 }
611
612 fn resolve(&self, name: &str, scopes: &[Scope], phase: Phase) -> Resolution {
613 self.table
614 .resolve(&Self::symbol(name, scopes), Namespace::Value, phase)
615 }
616 }
617
618 #[test]
619 fn taking_the_saved_names_leaves_the_table_empty() {
620 let mut world = World::new();
621 let scope = world.scope();
622 world.define("taken", &[scope], Phase::Runtime);
623 let everything = ScopeAllocator::default().next_scope()..world.scopes.next_scope();
624 world.table.take_saved(everything);
625 assert!(world.table.entries.is_empty());
626 }
627
628 #[test]
629 fn a_symbol_with_a_prelude_scope_finds_a_saved_name() {
630 let mut world = World::new();
631 let scope = world.scope();
632 let saved = world.define("saved", &[scope], Phase::Runtime);
633 world.save_names();
634 let symbol = World::symbol("saved", &[scope]);
635 let resolution = world
636 .table
637 .resolve(&symbol, Namespace::Value, Phase::Runtime);
638 assert_eq!(resolution, Resolution::Bound(saved));
639 }
640
641 #[test]
642 fn a_symbol_with_only_later_scopes_decodes_no_saved_name() {
643 let mut world = World::new();
644 let scope = world.scope();
645 world.define("saved", &[scope], Phase::Runtime);
646 world.save_names();
647 let later = world.scope();
648 let symbol = World::symbol("saved", &[later]);
649 world
650 .table
651 .resolve(&symbol, Namespace::Value, Phase::Runtime);
652 assert!(!world.table.saved.is_decoded("saved", Namespace::Value));
653 }
654
655 #[test]
656 fn a_symbol_with_only_earlier_scopes_decodes_no_saved_name() {
657 let mut world = World::new();
658 let earlier = world.scope();
659 let first = world.scopes.next_scope();
660 let scope = world.scope();
661 world.define("saved", &[scope], Phase::Runtime);
662 world.save_names_from(first);
663 let symbol = World::symbol("saved", &[earlier]);
664 world
665 .table
666 .resolve(&symbol, Namespace::Value, Phase::Runtime);
667 assert!(!world.table.saved.is_decoded("saved", Namespace::Value));
668 }
669
670 #[test]
671 fn a_shared_scope_chain_still_looks_in_the_saved_names() {
672 let mut world = World::new();
673 let scope = world.scope();
674 world.define("saved", &[scope], Phase::Runtime);
675 world.save_names();
676 let chain = world.chain(ScopeSet::SHORTEST_SHARED_PREFIX);
677 world.resolve_sharing("saved", &World::prefix(&chain));
678 assert!(world.table.saved.is_decoded("saved", Namespace::Value));
679 }
680
681 #[test]
682 #[should_panic(expected = "every saved name is bound under a prelude scope")]
683 fn a_saved_name_outside_the_prelude_scopes_stops_the_build() {
684 let mut world = World::new();
685 let scope = world.scope();
686 world.define("saved", &[scope], Phase::Runtime);
687 let later = world.scopes.next_scope();
688 world.table.take_saved(later..later);
689 }
690
691 #[test]
692 fn a_saved_type_name_is_listed_in_the_type_namespace_only() {
693 let mut world = World::new();
694 let scope = world.scope();
695 let saved = world.define_type("saved", &[scope]);
696 world.save_names();
697 let symbol = World::symbol("anything", &[scope]);
698 let types = world
699 .table
700 .visible_name_bindings(&symbol, Namespace::Type, Phase::Runtime);
701 let values = world
702 .table
703 .visible_name_bindings(&symbol, Namespace::Value, Phase::Runtime);
704 assert_eq!(types, vec![(Rc::from("saved"), saved)]);
705 assert!(values.is_empty());
706 }
707
708 #[test]
709 fn a_qualified_name_bound_again_after_a_save_is_recorded_once() {
710 let mut world = World::new();
711 let (scope, other) = (world.scope(), world.scope());
712 world.define("option/some", &[scope], Phase::Runtime);
713 world.save_names();
714 world.define("option/some", &[other], Phase::Runtime);
715 let recorded = world
716 .table
717 .qualified_names
718 .ending_in("some".into(), Namespace::Value);
719 assert_eq!(recorded.len(), 1);
720 }
721
722 #[test]
723 #[should_panic(expected = "every saved name is bound under a prelude scope")]
724 fn a_shared_saved_name_outside_the_prelude_scopes_stops_the_build() {
725 let mut world = World::new();
726 let chain = world.chain(ScopeSet::SHORTEST_SHARED_PREFIX);
727 world.define_sharing("saved", &World::prefix(&chain));
728 let later = world.scopes.next_scope();
729 world.table.take_saved(later..later);
730 }
731
732 #[test]
733 fn a_program_name_beside_a_saved_one_still_sees_the_saved_one() {
734 let mut world = World::new();
735 let scope = world.scope();
736 let saved = world.define("shared", &[scope], Phase::Runtime);
737 world.save_names();
738 let later = world.scope();
739 world.define("shared", &[later], Phase::Runtime);
740 let symbol = World::symbol("shared", &[scope]);
741 let resolve = || {
742 world
743 .table
744 .resolve(&symbol, Namespace::Value, Phase::Runtime)
745 };
746 assert_eq!(resolve(), Resolution::Bound(saved));
747 assert_eq!(resolve(), Resolution::Bound(saved));
748 }
749
750 #[test]
751 fn a_program_name_with_only_later_scopes_decodes_no_saved_name() {
752 let mut world = World::new();
753 let scope = world.scope();
754 world.define("shared", &[scope], Phase::Runtime);
755 world.save_names();
756 let later = world.scope();
757 world.define("shared", &[later], Phase::Runtime);
758 let symbol = World::symbol("shared", &[later]);
759 world
760 .table
761 .resolve(&symbol, Namespace::Value, Phase::Runtime);
762 assert!(!world.table.saved.is_decoded("shared", Namespace::Value));
763 }
764
765 #[test]
766 fn a_saved_name_is_listed_beside_the_programs_own() {
767 let mut world = World::new();
768 let scope = world.scope();
769 let saved = world.define("saved", &[scope], Phase::Runtime);
770 world.save_names();
771 let own = world.define("own", &[scope], Phase::Runtime);
772 let symbol = World::symbol("anything", &[scope]);
773 let mut listed =
774 world
775 .table
776 .visible_name_bindings(&symbol, Namespace::Value, Phase::Runtime);
777 listed.sort_by_key(|(_, binding)| *binding);
778 let bindings: Vec<BindingId> = listed.into_iter().map(|(_, binding)| binding).collect();
779 assert_eq!(bindings, vec![saved, own]);
780 }
781
782 #[test]
783 fn a_saved_binding_is_visible_beside_the_programs_own() {
784 let mut world = World::new();
785 let scope = world.scope();
786 let saved = world.define_type("saved", &[scope]);
787 world.save_names();
788 let own = world.define_type("own", &[scope]);
789 let scopes = World::scope_set(&[scope]);
790 let mut visible = world
791 .table
792 .visible_bindings(&scopes, Namespace::Type, Phase::Runtime);
793 visible.sort();
794 assert_eq!(visible, vec![saved, own]);
795 }
796
797 #[test]
798 fn a_saved_qualified_name_is_found_by_its_last_segment() {
799 let mut world = World::new();
800 let scope = world.scope();
801 let saved = world.define("option/some", &[scope], Phase::Runtime);
802 world.save_names();
803 let symbol = World::symbol("some", &[scope]);
804 let found = world.table.visible_qualified_bindings_ending_in(
805 &symbol,
806 Namespace::Value,
807 Phase::Runtime,
808 );
809 assert_eq!(found, vec![saved]);
810 }
811
812 #[test]
813 fn a_forgotten_binding_resolves_no_more() {
814 let mut world = World::new();
815 let scope = world.scope();
816 let kept = world.define("kept", &[scope], Phase::Runtime);
817 let forgotten = world.define("forgotten", &[scope], Phase::Runtime);
818 world.table.forget(|binding| binding == forgotten);
819 let resolve = |name| {
820 world.table.resolve(
821 &World::symbol(name, &[scope]),
822 Namespace::Value,
823 Phase::Runtime,
824 )
825 };
826 assert_eq!(resolve("forgotten"), Resolution::Unbound);
827 assert_eq!(resolve("kept"), Resolution::Bound(kept));
828 assert!(!world.table.holds(forgotten));
829 assert!(world.table.holds(kept));
830 }
831
832 #[test]
833 fn a_forgotten_sharing_binding_resolves_no_more() {
834 let mut world = World::new();
835 let chain = world.chain(ScopeSet::SHORTEST_SHARED_PREFIX);
836 let prefix = World::prefix(&chain);
837 let forgotten = world.define_sharing("shared", &prefix);
838 world.table.forget(|binding| binding == forgotten);
839 assert_eq!(
840 world.resolve_sharing("shared", &prefix),
841 Resolution::Unbound
842 );
843 }
844
845 #[test]
846 fn forgetting_every_binding_of_a_name_drops_the_name() {
847 let mut world = World::new();
848 let scope = world.scope();
849 let forgotten = world.define("gone", &[scope], Phase::Runtime);
850 world.table.forget(|binding| binding == forgotten);
851 assert!(world.table.entries.is_empty());
852 }
853
854 #[test]
855 fn forgetting_one_of_two_bindings_of_a_name_keeps_the_other() {
856 let mut world = World::new();
857 let (outer, inner) = (world.scope(), world.scope());
858 let wide = world.define("x", &[outer], Phase::Runtime);
859 let narrow = world.define("x", &[outer, inner], Phase::Runtime);
860 world.table.forget(|binding| binding == narrow);
861 let symbol = World::symbol("x", &[outer, inner]);
862 let resolution = world
863 .table
864 .resolve(&symbol, Namespace::Value, Phase::Runtime);
865 assert_eq!(resolution, Resolution::Bound(wide));
866 }
867
868 #[test]
869 fn the_binding_with_the_largest_subset_wins() {
870 let mut world = World::new();
871 let (module, inner) = (world.scope(), world.scope());
872 world.define("x", &[module], Phase::Runtime);
873 let shadow = world.define("x", &[module, inner], Phase::Runtime);
874 assert_eq!(
875 world.resolve("x", &[module, inner], Phase::Runtime),
876 Resolution::Bound(shadow)
877 );
878 }
879
880 #[test]
881 fn a_binding_outside_the_reference_scopes_is_invisible() {
882 let mut world = World::new();
883 let (module, macro_introduced) = (world.scope(), world.scope());
884 world.define("tmp", &[module, macro_introduced], Phase::Runtime);
885 assert_eq!(
886 world.resolve("tmp", &[module], Phase::Runtime),
887 Resolution::Unbound
888 );
889 }
890
891 #[test]
892 fn two_bindings_of_equal_size_are_ambiguous() {
893 let mut world = World::new();
894 let (module, left, right) = (world.scope(), world.scope(), world.scope());
895 world.define("x", &[module, left], Phase::Runtime);
896 world.define("x", &[module, right], Phase::Runtime);
897 let resolution = world.resolve("x", &[module, left, right], Phase::Runtime);
898 assert!(matches!(resolution, Resolution::Ambiguous(_)));
899 }
900
901 #[test]
902 fn a_larger_binding_settles_two_smaller_bindings_of_equal_size() {
903 let mut world = World::new();
904 let (module, left, right) = (world.scope(), world.scope(), world.scope());
905 world.define("x", &[module, left], Phase::Runtime);
906 world.define("x", &[module, right], Phase::Runtime);
907 let settled = world.define("x", &[module, left, right], Phase::Runtime);
908 assert_eq!(
909 world.resolve("x", &[module, left, right], Phase::Runtime),
910 Resolution::Bound(settled)
911 );
912 }
913
914 #[test]
915 fn compile_time_bindings_are_invisible_to_runtime_code() {
916 let mut world = World::new();
917 let module = world.scope();
918 world.define("name", &[module], Phase::CompileTime);
919 assert_eq!(
920 world.resolve("name", &[module], Phase::Runtime),
921 Resolution::Unbound
922 );
923 }
924
925 #[test]
926 fn rebinding_a_binding_to_its_own_scopes_is_accepted() {
927 let mut world = World::new();
928 let module = world.scope();
929 let binding = world.define("x", &[module], Phase::Runtime);
930 let rebound = world.table.bind(
931 &World::symbol("x", &[module]),
932 Namespace::Value,
933 binding,
934 Phase::Runtime,
935 );
936 assert_eq!(rebound, Ok(()));
937 }
938
939 #[test]
940 fn rebinding_the_same_scopes_reports_the_existing_binding() {
941 let mut world = World::new();
942 let module = world.scope();
943 let first = world.define("x", &[module], Phase::Runtime);
944 let info = BindingInfo::new("x".into(), BindingKind::Local, None);
945 let second = world.bindings.add(info);
946 let duplicate = world.table.bind(
947 &World::symbol("x", &[module]),
948 Namespace::Value,
949 second,
950 Phase::Runtime,
951 );
952 assert_eq!(duplicate, Err(first));
953 }
954
955 #[test]
956 fn a_long_binding_list_finds_what_a_full_scan_finds() {
957 let mut world = World::new();
958 let scopes: Vec<Scope> = (0..5).map(|_| world.scope()).collect();
959 let entries = world.define_under_subsets("x", &scopes, NameEntries::SHORT_LIST_LENGTH + 4);
960 let reference = [scopes[0], scopes[1], scopes[4]];
961 let scanned: Vec<BindingId> = entries
962 .iter()
963 .filter(|(subset, _)| subset.iter().all(|scope| reference.contains(scope)))
964 .map(|(_, binding)| *binding)
965 .collect();
966 let (_, exact) = entries
967 .iter()
968 .find(|(subset, _)| *subset == reference)
969 .expect("the reference scopes are a defined subset");
970 assert_eq!(world.visible(&reference), scanned);
971 assert_eq!(
972 world.resolve("x", &reference, Phase::Runtime),
973 Resolution::Bound(*exact)
974 );
975 }
976
977 #[test]
978 fn a_qualified_binding_is_found_by_its_last_segment() {
979 let mut world = World::new();
980 let module = world.scope();
981 let circle = world.define("shape/circle", &[module], Phase::Runtime);
982 let nested = world.define("geometry/shape/circle", &[module], Phase::Runtime);
983 world.define("circle", &[module], Phase::Runtime);
984 world.define("shape/square", &[module], Phase::Runtime);
985 assert_eq!(
986 world.visible_qualified_ending_in("circle", &[module]),
987 [circle, nested]
988 );
989 }
990
991 #[test]
992 fn a_qualified_binding_outside_the_reference_scopes_is_not_found() {
993 let mut world = World::new();
994 let (module, inner) = (world.scope(), world.scope());
995 world.define("shape/circle", &[module, inner], Phase::Runtime);
996 assert_eq!(world.visible_qualified_ending_in("circle", &[module]), []);
997 }
998
999 #[test]
1000 fn a_qualified_name_in_another_namespace_is_not_found() {
1001 let mut world = World::new();
1002 let module = world.scope();
1003 world.define_type("shape/circle", &[module]);
1004 assert_eq!(world.visible_qualified_ending_in("circle", &[module]), []);
1005 }
1006
1007 #[test]
1008 fn a_qualified_name_bound_twice_finds_each_binding_once() {
1009 let mut world = World::new();
1010 let (module, inner) = (world.scope(), world.scope());
1011 let outer = world.define("shape/circle", &[module], Phase::Runtime);
1012 let shadow = world.define("shape/circle", &[module, inner], Phase::Runtime);
1013 assert_eq!(
1014 world.visible_qualified_ending_in("circle", &[module, inner]),
1015 [outer, shadow]
1016 );
1017 }
1018
1019 #[test]
1020 fn a_binding_under_a_shared_prefix_is_visible_from_a_longer_prefix() {
1021 let mut world = World::new();
1022 let chain = world.chain(ScopeSet::SHORTEST_SHARED_PREFIX);
1023 let bound = world.define_sharing("x", &World::prefix(&chain));
1024 chain.push(world.scope());
1025 assert_eq!(
1026 world.resolve_sharing("x", &World::prefix(&chain)),
1027 Resolution::Bound(bound)
1028 );
1029 }
1030
1031 #[test]
1032 fn a_shared_binding_is_visible_from_plain_scopes_that_hold_its_prefix() {
1033 let mut world = World::new();
1034 let scopes: Vec<Scope> = (0..ScopeSet::SHORTEST_SHARED_PREFIX)
1035 .map(|_| world.scope())
1036 .collect();
1037 let chain = ScopeChain::default();
1038 scopes.iter().for_each(|scope| chain.push(*scope));
1039 let bound = world.define_sharing("x", &World::prefix(&chain));
1040 assert_eq!(
1041 world.resolve("x", &scopes, Phase::Runtime),
1042 Resolution::Bound(bound)
1043 );
1044 }
1045
1046 #[test]
1047 fn a_compile_time_shared_binding_is_invisible_to_runtime_code() {
1048 let mut world = World::new();
1049 let prefix = World::prefix(&world.chain(ScopeSet::SHORTEST_SHARED_PREFIX));
1050 let binding = world.new_binding("x");
1051 world
1052 .table
1053 .bind(
1054 &World::sharing_symbol("x", &prefix),
1055 Namespace::Value,
1056 binding,
1057 Phase::CompileTime,
1058 )
1059 .expect("no duplicate");
1060 assert_eq!(world.resolve_sharing("x", &prefix), Resolution::Unbound);
1061 }
1062
1063 #[test]
1064 fn a_plain_binding_beside_a_shared_one_sees_only_its_own_scopes() {
1065 let mut world = World::new();
1066 let chain = world.chain(ScopeSet::SHORTEST_SHARED_PREFIX);
1067 world.define_sharing("x", &World::prefix(&chain));
1068 let outside = world.scope();
1069 let plain = world.define("x", &[outside], Phase::Runtime);
1070 assert_eq!(
1071 world.resolve("x", &[outside], Phase::Runtime),
1072 Resolution::Bound(plain)
1073 );
1074 }
1075
1076 #[test]
1077 fn a_shared_prefix_sees_the_plain_binding_it_shadows_only_when_larger() {
1078 let mut world = World::new();
1079 let chain = world.chain(ScopeSet::SHORTEST_SHARED_PREFIX);
1080 let first = World::prefix(&chain).first();
1081 world.define("x", &[first], Phase::Runtime);
1082 let shadow = world.define_sharing("x", &World::prefix(&chain));
1083 assert_eq!(
1084 world.resolve_sharing("x", &World::prefix(&chain)),
1085 Resolution::Bound(shadow)
1086 );
1087 }
1088
1089 #[test]
1090 fn rebinding_shared_scopes_reports_the_existing_binding() {
1091 let mut world = World::new();
1092 let chain = world.chain(ScopeSet::SHORTEST_SHARED_PREFIX);
1093 let prefix = World::prefix(&chain);
1094 let first = world.define_sharing("x", &prefix);
1095 let second = world.new_binding("x");
1096 let duplicate = world.table.bind(
1097 &World::sharing_symbol("x", &prefix),
1098 Namespace::Value,
1099 second,
1100 Phase::Runtime,
1101 );
1102 assert_eq!(duplicate, Err(first));
1103 }
1104}