tan  0.0.1
type_precheck.cpp
1 #include "analysis/type_precheck.h"
2 #include "ast/ast_base.h"
3 #include "ast/ast_node_type.h"
4 #include "common/ast_visitor.h"
5 #include "ast/type.h"
6 #include "ast/expr.h"
7 #include "ast/stmt.h"
8 #include "ast/package.h"
9 #include "ast/decl.h"
10 #include "ast/intrinsic.h"
11 #include "ast/context.h"
12 #include "source_file/token.h"
13 #include "driver/driver.h"
14 #include <iostream>
15 
16 namespace tanlang {
17 
18 void TypePrecheck::default_visit(ASTBase *) { TAN_ASSERT(false); }
19 
20 void TypePrecheck::run_impl(Package *p) {
21  _package = p;
22 
23  push_scope(p);
24 
25  for (const auto &c : p->get_children()) {
26  switch (c->get_node_type()) {
27  case ASTNodeType::IMPORT:
28  CALL_AST_VISITOR(Import, c);
29  break;
30  case ASTNodeType::STRUCT_DECL:
31  CALL_AST_VISITOR(StructDecl, c);
32  break;
33  case ASTNodeType::FUNC_DECL:
34  CALL_AST_VISITOR(FunctionDecl, c);
35  break;
36  case ASTNodeType::INTRINSIC:
37  CALL_AST_VISITOR(Intrinsic, c);
38  break;
39  default:
40  break;
41  }
42  }
43 
44  pop_scope();
45 }
46 
47 Type *TypePrecheck::check_type_ref(Type *p, ASTBase *node) {
48  TAN_ASSERT(p->is_ref());
49  Type *ret = p;
50 
51  const str &referred_name = p->get_typename();
52  auto *decl = search_decl_in_scopes(referred_name);
53  if (decl && decl->is_type_decl()) {
54  ret = decl->get_type();
55  TAN_ASSERT(ret);
56  if (!ret->is_canonical()) {
57  _package->top_level_symbol_dependency.add_dependency(decl, node);
58  }
59  } else {
60  error(ErrorType::TYPE_ERROR, node, fmt::format("Unknown type {}", referred_name));
61  }
62 
63  return ret;
64 }
65 
66 Type *TypePrecheck::check_type(Type *p, ASTBase *node) {
67  TAN_ASSERT(p);
68  TAN_ASSERT(node);
69 
70  Type *ret = p;
71  if (p->is_ref()) {
72  ret = check_type_ref(p, node);
73  } else if (p->is_pointer()) {
74  auto *pointee = pcast<PointerType>(p)->get_pointee();
75 
76  TAN_ASSERT(pointee);
77  if (pointee->is_ref()) {
78  pointee = check_type_ref(pointee, node);
79  if (pointee->is_canonical()) {
80  ret = Type::GetPointerType(pointee);
81  }
82  }
83  }
84 
85  TAN_ASSERT(ret);
86  return ret;
87 }
88 
89 DEFINE_AST_VISITOR_IMPL(TypePrecheck, Import) {
90  str name = p->get_name();
91 
92  auto *compiler = CompilerDriver::instance();
93  TAN_ASSERT(compiler);
94  Package *package = compiler->get_package(name);
95  if (!package) {
96  error(ErrorType::IMPORT_ERROR, p, "Cannot find package named: " + name);
97  }
98 
99  Context *imported_ctx = package->ctx();
100 
101  // Imported declarations are stored in both the package's context and this import AST node:
102  // 1. The context only serves as a search table
103  // 2. The type checker and code generator will operate on the declarations stored in the import node
104 
105  // import functions
106  vector<FunctionDecl *> funcs = imported_ctx->get_func_decls();
107  for (auto *f : funcs) {
108  f->set_start(p->start());
109  f->set_end(p->end());
110 
111  if (f->is_public() || f->is_external()) {
112  // FIXME: merge multiple declarations of the same symbol, fail if they don't match
113  // for example, intrinsics
114  auto *existing = top_ctx()->get_func_decl(f->get_name());
115  if (!existing) {
116  p->_imported_funcs.push_back(f);
117  top_ctx()->set_function_decl(f);
118  }
119  }
120  }
121 
122  // imported types
123  vector<Decl *> decls = imported_ctx->get_decls();
124  for (auto *t : decls) {
125  if (t->is_type_decl() && t->is_public()) {
126  top_ctx()->set_decl(t->get_name(), t);
127  p->_imported_types.push_back(pcast<TypeDecl>(t));
128  }
129  }
130 }
131 
132 /*
133 DEFINE_AST_VISITOR_IMPL(TypePrecheck, Identifier) {
134  auto *referred = search_decl_in_scopes(p->get_name());
135  if (referred) {
136  if (referred->is_type_decl()) { /// refers to a type
137  auto *ty = check_type_ref(referred->get_type(), p->loc(), p);
138  p->set_type_ref(ty);
139  } else { /// refers to a variable
140  p->set_var_ref(VarRef::Create(p->loc(), p->get_name(), referred));
141  p->set_type(check_type(referred->get_type(), p->loc(), p));
142  }
143  } else {
144  error(p, "Unknown identifier");
145  }
146 }
147 */
148 
149 DEFINE_AST_VISITOR_IMPL(TypePrecheck, Intrinsic) {
150  // check children if this is @test_comp_error
151  if (p->get_intrinsic_type() == IntrinsicType::TEST_COMP_ERROR) {
152  auto *tce = pcast<TestCompError>(p->get_sub());
153  if (tce->_caught)
154  return;
155 
156  push_scope(p);
157 
158  try {
159  for (auto *c : tce->get_children())
160  visit(c);
161  } catch (const CompileException &e) {
162  std::cerr << fmt::format("Caught expected compile error: {}\nContinue compilation...\n", e.what());
163  tce->_caught = true;
164  }
165 
166  pop_scope();
167  }
168 }
169 
170 DEFINE_AST_VISITOR_IMPL(TypePrecheck, VarDecl) {
171  Type *ty = p->get_type();
172  if (ty) {
173  p->set_type(check_type(ty, p));
174  }
175 }
176 
177 DEFINE_AST_VISITOR_IMPL(TypePrecheck, ArgDecl) { p->set_type(check_type(p->get_type(), p)); }
178 
179 DEFINE_AST_VISITOR_IMPL(TypePrecheck, Assignment) {
180  auto *lhs = p->get_lhs();
181  visit(lhs);
182 
183  // at this stage, we find out the type of assignment only if it's specified
184  if (lhs->get_node_type() == ASTNodeType::VAR_DECL) {
185  p->set_type(pcast<Decl>(lhs)->get_type());
186  }
187 }
188 
189 DEFINE_AST_VISITOR_IMPL(TypePrecheck, FunctionDecl) {
190  push_scope(p);
191 
192  /// update return type
193  auto *func_type = pcast<FunctionType>(p->get_type());
194  auto *ret_type = check_type(func_type->get_return_type(), p);
195  func_type->set_return_type(ret_type);
196 
197  /// type_check_ast args
198  size_t n = p->get_n_args();
199  const auto &arg_decls = p->get_arg_decls();
200  vector<Type *> arg_types(n, nullptr);
201  for (size_t i = 0; i < n; ++i) {
202  visit(arg_decls[i]); /// args will be added to the scope here
203  arg_types[i] = arg_decls[i]->get_type();
204  }
205  func_type->set_arg_types(arg_types); /// update arg types
206 
207  pop_scope();
208 }
209 
210 DEFINE_AST_VISITOR_IMPL(TypePrecheck, StructDecl) {
211  str struct_name = p->get_name();
212 
213  auto members = p->get_member_decls();
214  size_t n = members.size();
215  auto *ty = pcast<StructType>(p->get_type());
216  TAN_ASSERT(ty);
217 
218  push_scope(p);
219 
220  for (size_t i = 0; i < n; ++i) {
221  Expr *m = members[i];
222 
223  // Check if m is a struct member declaration before visiting
224  switch (m->get_node_type()) {
225  case ASTNodeType::VAR_DECL:
226  case ASTNodeType::FUNC_DECL:
227  break;
228  case ASTNodeType::ASSIGN: {
229  auto *assign = pcast<Assignment>(m);
230  if (assign->get_lhs()->get_node_type() != ASTNodeType::VAR_DECL)
231  error(ErrorType::SEMANTIC_ERROR, assign, "Expect a member variable declaration");
232  break;
233  }
234  default:
235  error(ErrorType::SEMANTIC_ERROR, p, "Invalid struct member");
236  }
237 
238  visit(m);
239 
240  /*
241  * DO NOT add unresolved symbol dependency if m's type is a pointer to an unresolved type reference
242  * This allows us to define a struct that holds a pointer to itself, like LinkedList.
243  *
244  * This works because:
245  * 1. m is registered in the unresolved symbol dependency graph so it will be re-analyzed in
246  * the final analysis stage.
247  * 2. Nothing actually directly relies on the type of m. For example, size in bits is always the size of a
248  * pointer.
249  */
250  if (!m->get_type()->is_canonical() && !m->get_type()->is_pointer()) {
251  _package->top_level_symbol_dependency.add_dependency(m, p);
252  }
253 
254  if (m->get_node_type() == ASTNodeType::VAR_DECL) { // member variable without initial value
255  str name = pcast<VarDecl>(m)->get_name();
256  p->set_member_index(name, (int)i);
257  (*ty)[i] = m->get_type();
258 
259  } else if (m->get_node_type() == ASTNodeType::ASSIGN) { // member variable with an initial value
260  auto *assign = pcast<Assignment>(m);
261  auto decl = pcast<VarDecl>(assign->get_lhs());
262 
263  (*ty)[i] = decl->get_type();
264 
265  // member name -> index
266  p->set_member_index(decl->get_name(), (int)i);
267 
268  // set rhs of assignment as the default value of this member
269  auto *rhs = assign->get_rhs();
270  if (!rhs->is_comptime_known()) {
271  error(ErrorType::SEMANTIC_ERROR, rhs, "Expect the value to be compile time known");
272  }
273  p->set_member_default_val((int)i, rhs);
274 
275  } else if (m->get_node_type() == ASTNodeType::FUNC_DECL) { // member functions
276  auto f = pcast<FunctionDecl>(m);
277 
278  (*ty)[i] = f->get_type();
279  p->set_member_index(f->get_name(), (int)i);
280  } else {
281  TAN_ASSERT(false);
282  }
283  }
284 
285  pop_scope();
286 }
287 
288 } // namespace tanlang