1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use std::collections::HashMap;
use codespan::Span;
use codespan_reporting::diagnostic::{Diagnostic, Label};
use legion::{world::SubWorld, Entity, Query};
use crate::{
lowering::{Name, NameTable},
Diagnostics,
};
#[legion::system]
pub(crate) fn run(
world: &mut SubWorld,
#[resource] diags: &mut Diagnostics,
#[resource] names: &mut NameTable,
named_items: &mut Query<(Entity, &Name, &Span)>,
) {
names.clear();
let mut lookup_table: HashMap<&Name, Vec<_>> = HashMap::new();
named_items.for_each(world, |(e, n, s)| {
let items = lookup_table.entry(n).or_default();
items.push((e, s));
items.sort_by_key(|(_, &s)| s);
});
for (name, items) in lookup_table {
match items.as_slice() {
[] => unreachable!(),
[(&ent, _)] => {
names.insert(name.clone(), ent);
},
[(&ent, &first_definition), others @ ..] => {
let diag = duplicate_name_diagnostic(
name,
first_definition,
others.iter().map(|(_, &s)| s),
);
diags.push(diag);
names.insert(name.clone(), ent);
},
}
}
}
fn duplicate_name_diagnostic(
name: &Name,
first_definition: Span,
duplicates: impl Iterator<Item = Span>,
) -> Diagnostic<()> {
let primary = Label::primary((), first_definition)
.with_message("The first definition is here");
let mut labels = vec![primary];
for duplicate in duplicates {
labels.push(
Label::secondary((), duplicate).with_message("Redefined here"),
);
}
Diagnostic::error()
.with_message(format!(
"The name \"{}\" is defined multiple times",
name
))
.with_labels(labels)
}