rucc_sema/scope.rs
1//! The scopes semantic analysis keeps, and what a name means in each of them.
2//!
3//! Design: `spec/07-types-and-semantics.md` section 7.4.
4//!
5//! The scoping itself is [`ScopeMap`], in `rucc-base`, because the parser keeps the same
6//! structure with different values in it. What is here is the values: C's namespaces, and what
7//! a name in each of them resolves to once the declaration it refers to has been checked.
8//!
9//! Two of C's four namespaces are here. Labels are function wide rather than block scoped, so
10//! the function checker holds them in a flat map and this stack would only be in the way.
11//! Members belong to the record that declares them and are reached through a type rather than
12//! through a scope, so they are a question for the type table.
13//!
14//! # Why the parser's answer is not enough
15//!
16//! The parser already resolved names, in the sense that it decided which of them were type
17//! names. That is a different question and a smaller one: it needed to know whether `A` in
18//! `(A)*b` was a type, and it never needed to know which `A`. This has to know which
19//! declaration a use refers to, because the answer is what the use gets its type from and what
20//! the object file eventually refers to.
21
22use rucc_base::{ScopeMap, Symbol};
23use rucc_types::TypeId;
24
25use crate::decl::DeclId;
26
27/// What an ordinary identifier names.
28///
29/// The four things C's ordinary namespace holds, which is objects, functions, typedef names and
30/// enumerators. The first two are the same case here because a use of either is a use of a
31/// declaration, and what separates them is the type it has.
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub enum Binding {
34 /// An object or a function, which is a declaration in the typed tree.
35 Decl(DeclId),
36 /// A `typedef` name, which is a name for a type and never appears in the tree.
37 Typedef(TypeId),
38 /// An enumerator, which is a constant and is folded into the expression that used it.
39 Enumerator {
40 /// The value, in the enumeration's underlying type.
41 value: i128,
42 /// The type the constant has, which is the enumeration in C23 and `int` before it.
43 ty: TypeId,
44 },
45}
46
47/// Which keyword introduced a tag.
48///
49/// A mismatch is an error and the diagnostic has to name what was declared, so the three are
50/// kept apart rather than collapsed into the type they name.
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52pub enum TagKind {
53 /// `struct`.
54 Struct,
55 /// `union`.
56 Union,
57 /// `enum`.
58 Enum,
59}
60
61impl TagKind {
62 /// How the keyword is spelled in a diagnostic.
63 #[must_use]
64 pub const fn as_str(self) -> &'static str {
65 match self {
66 TagKind::Struct => "struct",
67 TagKind::Union => "union",
68 TagKind::Enum => "enum",
69 }
70 }
71}
72
73/// A tag, and the type it names.
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75pub struct Tag {
76 /// Which keyword declared it.
77 pub kind: TagKind,
78 /// The type, which exists from the point the tag is first mentioned and is incomplete
79 /// until the definition is read.
80 pub ty: TypeId,
81}
82
83/// The scopes of one translation unit.
84#[derive(Debug, Default)]
85pub struct Scopes {
86 ordinary: ScopeMap<Binding>,
87 tags: ScopeMap<Tag>,
88}
89
90impl Scopes {
91 /// Empty scopes, with the file scope open.
92 #[must_use]
93 pub fn new() -> Scopes {
94 Scopes::default()
95 }
96
97 /// Opens a scope in every namespace.
98 ///
99 /// Both are pushed together because C opens them together. A parameter list is a scope of
100 /// its own, which is why the tag in `void f(struct S *p);` is gone by the next declaration,
101 /// and getting that wrong in one namespace and not the other is how the two drift.
102 pub fn push(&mut self) {
103 self.ordinary.push();
104 self.tags.push();
105 }
106
107 /// Closes the innermost scope in every namespace.
108 ///
109 /// # Panics
110 ///
111 /// Panics on closing the file scope.
112 pub fn pop(&mut self) {
113 self.ordinary.pop();
114 self.tags.pop();
115 }
116
117 /// Whether the only open scope is the file scope.
118 #[must_use]
119 pub fn at_file_scope(&self) -> bool {
120 self.ordinary.at_file_scope()
121 }
122
123 /// How many scopes are open, the file scope counting as one.
124 #[must_use]
125 pub fn depth(&self) -> u32 {
126 self.ordinary.depth()
127 }
128
129 /// Binds an ordinary identifier, and gives back what it was bound to in the same scope.
130 ///
131 /// A returned value is a redeclaration, which is the caller's to judge, since `int x; int
132 /// x;` is one object at file scope and an error inside a function.
133 pub fn declare(&mut self, name: Symbol, binding: Binding) -> Option<Binding> {
134 self.ordinary.declare(name, binding)
135 }
136
137 /// Binds an ordinary identifier in the file scope from wherever the checking is.
138 ///
139 /// For a builtin, which C says the implementation declared and which therefore was not
140 /// declared in whichever block first called it. Answers whether it took, which it does
141 /// only when nothing else binds the name.
142 pub fn declare_at_file_scope(&mut self, name: Symbol, binding: Binding) -> bool {
143 self.ordinary.declare_at_file_scope(name, binding)
144 }
145
146 /// What an ordinary identifier names here.
147 #[must_use]
148 pub fn lookup(&self, name: Symbol) -> Option<Binding> {
149 self.ordinary.get(name)
150 }
151
152 /// What an ordinary identifier names in the innermost scope that binds it to a binding
153 /// `wanted` takes, looking outwards.
154 #[must_use]
155 pub fn lookup_where(&self, name: Symbol, wanted: impl Fn(Binding) -> bool) -> Option<Binding> {
156 self.ordinary.get_where(name, wanted)
157 }
158
159 /// What an ordinary identifier names in the innermost scope alone.
160 #[must_use]
161 pub fn lookup_here(&self, name: Symbol) -> Option<Binding> {
162 self.ordinary.get_here(name)
163 }
164
165 /// Binds a tag, and gives back what it was bound to in the same scope.
166 pub fn declare_tag(&mut self, name: Symbol, tag: Tag) -> Option<Tag> {
167 self.tags.declare(name, tag)
168 }
169
170 /// What tag a name names here.
171 #[must_use]
172 pub fn tag(&self, name: Symbol) -> Option<Tag> {
173 self.tags.get(name)
174 }
175
176 /// What tag a name names in the innermost scope alone.
177 ///
178 /// This is the question `struct S;` asks, since a bare declaration of a tag declares a new
179 /// type in this scope even where an outer one is visible, and `struct S *p;` asks the other
180 /// one, since it refers to whatever `S` already means.
181 #[must_use]
182 pub fn tag_here(&self, name: Symbol) -> Option<Tag> {
183 self.tags.get_here(name)
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use rucc_base::Idx;
190 use rucc_types::{IntKind, Types};
191
192 use super::*;
193
194 const S: Symbol = Symbol::from_raw(1);
195
196 #[test]
197 fn a_tag_and_an_ordinary_name_do_not_disturb_each_other() {
198 let types = Types::new();
199 let int = types.int(IntKind::Int);
200 let mut scopes = Scopes::new();
201
202 scopes.declare(S, Binding::Typedef(int));
203 scopes.declare_tag(S, Tag { kind: TagKind::Struct, ty: int });
204
205 assert_eq!(scopes.lookup(S), Some(Binding::Typedef(int)));
206 assert_eq!(scopes.tag(S).map(|tag| tag.kind), Some(TagKind::Struct));
207 }
208
209 #[test]
210 fn an_inner_declaration_hides_an_outer_one_until_its_scope_closes() {
211 let outer = Binding::Decl(Idx::from_usize(0));
212 let inner = Binding::Decl(Idx::from_usize(1));
213 let mut scopes = Scopes::new();
214
215 scopes.declare(S, outer);
216 scopes.push();
217 assert_eq!(scopes.declare(S, inner), None);
218 assert_eq!(scopes.lookup(S), Some(inner));
219 // Which is what makes a use resolve to a declaration rather than to a name.
220 scopes.pop();
221 assert_eq!(scopes.lookup(S), Some(outer));
222 }
223
224 #[test]
225 fn a_tag_declared_again_in_an_inner_scope_is_a_new_type() {
226 let types = Types::new();
227 let int = types.int(IntKind::Int);
228 let long = types.int(IntKind::Long);
229 let mut scopes = Scopes::new();
230
231 scopes.declare_tag(S, Tag { kind: TagKind::Struct, ty: int });
232 scopes.push();
233 // `struct S;` asks what is bound here and finds nothing, so it declares a new type.
234 assert_eq!(scopes.tag_here(S), None);
235 scopes.declare_tag(S, Tag { kind: TagKind::Struct, ty: long });
236 assert_eq!(scopes.tag(S).map(|tag| tag.ty), Some(long));
237 scopes.pop();
238 assert_eq!(scopes.tag(S).map(|tag| tag.ty), Some(int));
239 }
240
241 #[test]
242 fn a_redeclaration_in_one_scope_says_what_it_was() {
243 let first = Binding::Decl(Idx::from_usize(0));
244 let second = Binding::Decl(Idx::from_usize(1));
245 let mut scopes = Scopes::new();
246
247 assert_eq!(scopes.declare(S, first), None);
248 assert_eq!(scopes.declare(S, second), Some(first));
249 }
250}