Thorin 1.9.0
The Higher ORder INtermediate representation
Loading...
Searching...
No Matches
bind.cpp
Go to the documentation of this file.
1#include "thorin/ast/ast.h"
2
3using namespace std::literals;
4
5namespace thorin::ast {
6
7using Tag = Tok::Tag;
8
9class DummyDecl : public Decl {
10public:
12 : Decl(Loc()) {}
13
14 std::ostream& stream(Tab&, std::ostream& os) const override { return os << "<dummy>"; }
15};
16
17class Scopes {
18public:
19 using Scope = fe::SymMap<std::pair<Loc, const Decl*>>;
20
22 : ast_(ast)
23 , dummy_(ast.ptr<DummyDecl>()) {
24 push(); // root scope
25 }
26
27 AST& ast() const { return ast_; }
28 Driver& driver() const { return ast().driver(); }
29 Scope& top() { return scopes_.back(); }
30 const Decl* dummy() const { return dummy_.get(); }
31
32 void push() { scopes_.emplace_back(); }
33
34 void pop() {
35 assert(!scopes_.empty());
36 scopes_.pop_back();
37 }
38
39 const Decl* find(Dbg dbg, bool quiet = false) {
40 if (dbg.is_anon()) return nullptr;
41
42 for (auto& scope : scopes_ | std::ranges::views::reverse)
43 if (auto i = scope.find(dbg.sym()); i != scope.end()) return i->second.second;
44
45 if (!quiet) {
46 ast().error(dbg.loc(), "'{}' not found", dbg.sym());
47 bind(dbg, dummy()); // put into scope to prevent further errors
48 }
49 return nullptr;
50 }
51
52 void bind(Dbg dbg, const Decl* decl, bool rebind = false, bool quiet = false) {
53 if (dbg.is_anon()) return;
54
55 if (rebind) {
56 top()[dbg.sym()] = std::pair(dbg.loc(), decl);
57 } else if (auto [i, ins] = top().emplace(dbg.sym(), std::pair(dbg.loc(), decl)); !ins) {
58 auto [prev_loc, prev_decl] = i->second;
59 if (!quiet && !prev_decl->isa<DummyDecl>()) { // if prev_decl stems from an error - don't complain
60 ast().error(dbg.loc(), "redeclaration of '{}'", dbg);
61 ast().note(prev_loc, "previous declaration here");
62 }
63 }
64 }
65
66private:
67 AST& ast_;
68 Ptr<DummyDecl> dummy_;
69 std::deque<Scope> scopes_;
70 absl::flat_hash_map<plugin_t, tag_t> plugin2tag_;
71};
72
73/*
74 * Module
75 */
76
77void Module::bind(AST& ast) const {
78 auto scopes = Scopes(ast);
79 bind(scopes);
80}
81
82void Module::bind(Scopes& s) const {
83 for (const auto& import : implicit_imports()) import->bind(s);
84 for (const auto& import : imports()) import->bind(s);
85 for (const auto& decl : decls()) decl->bind(s);
86}
87
88void Import::bind(Scopes& s) const { module()->bind(s); }
89
90/*
91 * Ptrn
92 */
93
94void IdPtrn::bind(Scopes& s, bool quiet) const {
95 if (!quiet && type()) type()->bind(s);
96 s.bind(dbg(), this, rebind(), quiet);
97}
98
99void TuplePtrn::bind(Scopes& s, bool quiet) const {
100 for (const auto& ptrn : ptrns()) ptrn->bind(s, quiet);
101 s.bind(dbg(), this, rebind(), quiet);
102}
103
104void GrpPtrn::bind(Scopes& s, bool quiet) const { s.bind(dbg(), this, rebind(), quiet); }
105
106/*
107 * Expr
108 */
109
110// clang-format off
111void IdExpr ::bind(Scopes& s) const { decl_ = s.find(dbg()); }
112void TypeExpr ::bind(Scopes& s) const { level()->bind(s); }
113void ErrorExpr ::bind(Scopes&) const {}
114void InferExpr ::bind(Scopes&) const {}
116// clang-format on
117
118void LitExpr::bind(Scopes& s) const {
119 if (type()) {
120 type()->bind(s);
121 if (tag() == Tag::L_str || tag() == Tag::L_c || tag() == Tag::L_i)
122 s.ast().error(type()->loc(), "a {} shall not have a type annotation", tag());
123 } else {
124 if (tag() == Tag::L_f) s.ast().error(loc(), "type annotation mandatory for floating point literal");
125 }
126}
127
128void DeclExpr::bind(Scopes& s) const {
129 if (is_where())
130 for (const auto& decl : decls() | std::ranges::views::reverse) decl->bind(s);
131 else
132 for (const auto& decl : decls()) decl->bind(s);
133 expr()->bind(s);
134}
135
136void BlockExpr::bind(Scopes& s) const {
137 s.push();
138 expr()->bind(s);
139 s.pop();
140}
141
142void ArrowExpr::bind(Scopes& s) const {
143 dom()->bind(s);
144 codom()->bind(s);
145}
146
147void PiExpr::Dom::bind(Scopes& s, bool quiet) const {
148 ptrn()->bind(s, quiet);
149 if (ret()) ret()->bind(s, quiet);
150}
151
152void PiExpr::bind(Scopes& s) const {
153 s.push();
154 for (const auto& dom : doms()) dom->bind(s);
155 if (codom()) {
156 if (tag() == Tag::K_Cn) s.ast().error(codom()->loc(), "a continuation shall not have a codomain");
157 codom()->bind(s);
158 }
159 s.pop();
160}
161
162void LamExpr::bind(Scopes& s) const {
163 lam()->bind_decl(s);
164 lam()->bind_body(s);
165}
166
167void AppExpr::bind(Scopes& s) const {
168 callee()->bind(s);
169 arg()->bind(s);
170}
171
172void RetExpr::bind(Scopes& s) const {
173 callee()->bind(s);
174 arg()->bind(s);
175 ptrn()->bind(s);
176 body()->bind(s);
177}
178
179void SigmaExpr::bind(Scopes& s) const {
180 s.push();
181 ptrn()->bind(s);
182 s.pop();
183}
184
185void TupleExpr::bind(Scopes& s) const {
186 for (const auto& elem : elems()) elem->bind(s);
187}
188
189template<bool arr> void ArrOrPackExpr<arr>::bind(Scopes& s) const {
190 s.push();
191 shape()->bind(s);
192 body()->bind(s);
193 s.pop();
194}
195
196template void ArrOrPackExpr<true>::bind(Scopes&) const;
197template void ArrOrPackExpr<false>::bind(Scopes&) const;
198
199void ExtractExpr::bind(Scopes& s) const {
200 tuple()->bind(s);
201 if (auto expr = std::get_if<Ptr<Expr>>(&index()))
202 (*expr)->bind(s);
203 else {
204 auto dbg = std::get<Dbg>(index());
205 decl_ = s.find(dbg, true);
206 }
207}
208
209void InsertExpr::bind(Scopes& s) const {
210 tuple()->bind(s);
211 index()->bind(s);
212 value()->bind(s);
213}
214
215/*
216 * Decl
217 */
218
219void AxiomDecl::Alias::bind(Scopes& s, const AxiomDecl* axiom) const {
220 auto sym = s.ast().sym(axiom->dbg().sym().str() + "."s + dbg().sym().str());
221 full_ = Dbg(dbg().loc(), sym);
222 s.bind(full_, this);
223}
224
225void AxiomDecl::bind(Scopes& s) const {
226 type()->bind(s);
227 annex_ = s.ast().name2annex(dbg(), nullptr);
228
229 if (annex_->fresh)
230 annex_->normalizer = normalizer();
231 else if (annex_->normalizer.sym() != normalizer().sym()) {
232 auto l = normalizer().loc() ? normalizer().loc() : loc().anew_finis();
233 s.ast().error(l, "normalizer mismatch for axiom '{}'", dbg());
234 if (auto norm = annex_->normalizer)
235 s.ast().note(norm.loc(), "previous normalizer '{}'", norm);
236 else
237 s.ast().note(l, "initially no normalizer specified");
238 }
239
240 if (num_subs() == 0) {
241 s.bind(dbg(), this);
242 } else {
243 if (auto old = s.find(dbg(), true)) {
244 if (auto old_ax = old->isa<AxiomDecl>()) {
245 if (old_ax->num_subs() == 0) {
246 s.ast().error(dbg().loc(), "redeclared sub-less axiom '{}' with subs", dbg());
247 s.ast().note(old_ax->dbg().loc(), "previous location here");
248 }
249 }
250 }
251 for (const auto& aliases : subs())
252 for (const auto& alias : aliases) alias->bind(s, this);
253 }
254}
255
256void LetDecl::bind(Scopes& s) const {
257 s.push();
258 value()->bind(s);
259 s.pop();
260 ptrn()->bind(s);
261
262 if (auto id = ptrn()->isa<IdPtrn>()) annex_ = s.ast().name2annex(id->dbg(), &sub_);
263}
264
265void RecDecl::bind(Scopes& s) const {
266 for (auto curr = this; curr; curr = curr->next()) curr->bind_decl(s);
267 for (auto curr = this; curr; curr = curr->next()) curr->bind_body(s);
268 annex_ = s.ast().name2annex(dbg(), &sub_);
269}
270
272 if (auto t = type()) t->bind(s);
273 if (!type()->isa<InferExpr>() && body()->isa<LamExpr>())
274 s.ast().warn(type()->loc(), "type of recursive declaration ignored for function expression");
275
276 if (!body()->isa<LamExpr>() && !body()->isa<PiExpr>() && !body()->isa<SigmaExpr>())
277 s.ast().error(body()->loc(), "unsupported expression for a recursive declaration");
278
279 s.bind(dbg(), this);
280}
281
282void RecDecl::bind_body(Scopes& s) const { body()->bind(s); }
283
284void LamDecl::Dom::bind(Scopes& s, bool quiet) const {
285 PiExpr::Dom::bind(s, quiet);
286
287 if (filter() && !quiet) filter()->bind(s);
288}
289
291 s.push();
292 for (size_t i = 0, e = num_doms(); i != e; ++i) dom(i)->bind(s);
293
294 if (auto filter = doms().back()->filter()) {
295 if (auto pe = filter->isa<PrimaryExpr>()) {
296 if (pe->tag() == Tag::K_tt && (tag() == Tag::K_lam || tag() == Tag::T_lm))
297 s.ast().warn(filter->loc(),
298 "'.tt'-filter superfluous as the last curried function group of a '{}' receives a "
299 "'.tt'-filter by default",
300 tag());
301 if (pe->tag() == Tag::K_ff && (tag() != Tag::K_lam && tag() != Tag::T_lm))
302 s.ast().warn(filter->loc(),
303 "'.ff'-filter superfluous as the last curried function group of a '{}' receives a "
304 "'.ff'-filter by default",
305 tag());
306 }
307 }
308
309 if (codom()) {
310 if (tag() == Tag::K_con || tag() == Tag::K_cn)
311 s.ast().error(codom()->loc(), "a continuation shall not have a codomain");
312 codom()->bind(s);
313 }
314
315 s.pop();
316 s.bind(dbg(), this);
317 annex_ = s.ast().name2annex(dbg(), &sub_);
318}
319
321 s.push();
322 for (const auto& dom : doms()) dom->bind(s, true);
323 body()->bind(s);
324 s.pop();
325}
326
327void CDecl::bind(Scopes& s) const {
328 s.push();
329 dom()->bind(s);
330 s.pop(); // we don't allow codom to depent on dom
331 if (codom()) codom()->bind(s);
332 s.bind(dbg(), this);
333}
334
335} // namespace thorin::ast
Some "global" variables needed all over the place.
Definition driver.h:17
Keeps track of indentation level.
Definition print.h:196
Error & error()
Definition ast.h:63
Error & note(Loc loc, const char *fmt, Args &&... args) const
Definition ast.h:86
Driver & driver()
Definition ast.h:62
void bind(Scopes &) const override
Definition bind.cpp:167
void bind(Scopes &) const override
Definition bind.cpp:189
void bind(Scopes &) const override
Definition bind.cpp:142
void bind(Scopes &, const AxiomDecl *) const
Definition bind.cpp:219
.ax ptrn: type = value;
Definition ast.h:723
Dbg dbg() const
Definition ast.h:752
void bind(Scopes &) const override
Definition bind.cpp:225
const Expr * expr() const
Definition ast.h:366
void bind(Scopes &) const override
Definition bind.cpp:136
void bind(Scopes &) const override
Definition bind.cpp:327
const auto & decls() const
Definition ast.h:386
bool is_where() const
Definition ast.h:387
const Expr * expr() const
Definition ast.h:388
void bind(Scopes &) const override
Definition bind.cpp:128
std::ostream & stream(Tab &, std::ostream &os) const override
Definition bind.cpp:14
virtual void bind(Scopes &) const =0
void bind(Scopes &) const override
Definition bind.cpp:199
void bind(Scopes &, bool quiet=false) const override
Definition bind.cpp:104
const Expr * type() const
Definition ast.h:202
void bind(Scopes &, bool quiet=false) const override
Definition bind.cpp:94
const Module * module() const
Definition ast.h:915
void bind(Scopes &) const
Definition bind.cpp:88
void bind(Scopes &) const override
Definition bind.cpp:209
void bind(Scopes &scopes, bool quiet=false) const override
Definition bind.cpp:284
void bind_decl(Scopes &) const override
Definition bind.cpp:290
void bind_body(Scopes &) const override
Definition bind.cpp:320
void bind(Scopes &) const override
Definition bind.cpp:162
void bind(Scopes &) const override
Definition bind.cpp:256
void bind(Scopes &) const override
Definition bind.cpp:118
Tok::Tag tag() const
Definition ast.h:345
const Expr * type() const
Definition ast.h:346
void bind(AST &) const
Definition bind.cpp:77
const auto & decls() const
Definition ast.h:943
const auto & imports() const
Definition ast.h:942
const auto & implicit_imports() const
Definition ast.h:941
Loc loc() const
Definition ast.h:121
virtual void bind(Scopes &scopes, bool quiet=false) const
Definition bind.cpp:147
const IdPtrn * ret() const
Definition ast.h:458
const Ptrn * ptrn() const
Definition ast.h:457
void bind(Scopes &) const override
Definition bind.cpp:152
void bind(Scopes &) const override
Definition bind.cpp:115
virtual void bind(Scopes &, bool quiet=false) const =0
bool rebind() const
Definition ast.h:178
Dbg dbg() const
Definition ast.h:179
virtual void bind_decl(Scopes &) const
Definition bind.cpp:271
void bind(Scopes &) const override
Definition bind.cpp:265
virtual void bind_body(Scopes &) const
Definition bind.cpp:282
void bind(Scopes &) const override
Definition bind.cpp:172
const Decl * dummy() const
Definition bind.cpp:30
void bind(Dbg dbg, const Decl *decl, bool rebind=false, bool quiet=false)
Definition bind.cpp:52
fe::SymMap< std::pair< Loc, const Decl * > > Scope
Definition bind.cpp:19
Driver & driver() const
Definition bind.cpp:28
Scopes(AST &ast)
Definition bind.cpp:21
AST & ast() const
Definition bind.cpp:27
Scope & top()
Definition bind.cpp:29
const Decl * find(Dbg dbg, bool quiet=false)
Definition bind.cpp:39
void bind(Scopes &) const override
Definition bind.cpp:179
void bind(Scopes &) const override
Definition bind.cpp:185
const Ptrn * ptrn(size_t i) const
Definition ast.h:252
const auto & ptrns() const
Definition ast.h:251
void bind(Scopes &, bool quiet=false) const override
Definition bind.cpp:99
fe::Arena::Ptr< const T > Ptr
Definition ast.h:21
Sym sym() const
Definition dbg.h:145