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 alone.
153 #[must_use]
154 pub fn lookup_here(&self, name: Symbol) -> Option<Binding> {
155 self.ordinary.get_here(name)
156 }
157
158 /// Binds a tag, and gives back what it was bound to in the same scope.
159 pub fn declare_tag(&mut self, name: Symbol, tag: Tag) -> Option<Tag> {
160 self.tags.declare(name, tag)
161 }
162
163 /// What tag a name names here.
164 #[must_use]
165 pub fn tag(&self, name: Symbol) -> Option<Tag> {
166 self.tags.get(name)
167 }
168
169 /// What tag a name names in the innermost scope alone.
170 ///
171 /// This is the question `struct S;` asks, since a bare declaration of a tag declares a new
172 /// type in this scope even where an outer one is visible, and `struct S *p;` asks the other
173 /// one, since it refers to whatever `S` already means.
174 #[must_use]
175 pub fn tag_here(&self, name: Symbol) -> Option<Tag> {
176 self.tags.get_here(name)
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use rucc_base::Idx;
183 use rucc_types::{IntKind, Types};
184
185 use super::*;
186
187 const S: Symbol = Symbol::from_raw(1);
188
189 #[test]
190 fn a_tag_and_an_ordinary_name_do_not_disturb_each_other() {
191 let types = Types::new();
192 let int = types.int(IntKind::Int);
193 let mut scopes = Scopes::new();
194
195 scopes.declare(S, Binding::Typedef(int));
196 scopes.declare_tag(S, Tag { kind: TagKind::Struct, ty: int });
197
198 assert_eq!(scopes.lookup(S), Some(Binding::Typedef(int)));
199 assert_eq!(scopes.tag(S).map(|tag| tag.kind), Some(TagKind::Struct));
200 }
201
202 #[test]
203 fn an_inner_declaration_hides_an_outer_one_until_its_scope_closes() {
204 let outer = Binding::Decl(Idx::from_usize(0));
205 let inner = Binding::Decl(Idx::from_usize(1));
206 let mut scopes = Scopes::new();
207
208 scopes.declare(S, outer);
209 scopes.push();
210 assert_eq!(scopes.declare(S, inner), None);
211 assert_eq!(scopes.lookup(S), Some(inner));
212 // Which is what makes a use resolve to a declaration rather than to a name.
213 scopes.pop();
214 assert_eq!(scopes.lookup(S), Some(outer));
215 }
216
217 #[test]
218 fn a_tag_declared_again_in_an_inner_scope_is_a_new_type() {
219 let types = Types::new();
220 let int = types.int(IntKind::Int);
221 let long = types.int(IntKind::Long);
222 let mut scopes = Scopes::new();
223
224 scopes.declare_tag(S, Tag { kind: TagKind::Struct, ty: int });
225 scopes.push();
226 // `struct S;` asks what is bound here and finds nothing, so it declares a new type.
227 assert_eq!(scopes.tag_here(S), None);
228 scopes.declare_tag(S, Tag { kind: TagKind::Struct, ty: long });
229 assert_eq!(scopes.tag(S).map(|tag| tag.ty), Some(long));
230 scopes.pop();
231 assert_eq!(scopes.tag(S).map(|tag| tag.ty), Some(int));
232 }
233
234 #[test]
235 fn a_redeclaration_in_one_scope_says_what_it_was() {
236 let first = Binding::Decl(Idx::from_usize(0));
237 let second = Binding::Decl(Idx::from_usize(1));
238 let mut scopes = Scopes::new();
239
240 assert_eq!(scopes.declare(S, first), None);
241 assert_eq!(scopes.declare(S, second), Some(first));
242 }
243}